Skip to content

Commit

Permalink
Merge pull request #307 from Microsoft/nturinski/installFuncCore
Browse files Browse the repository at this point in the history
Install func core
  • Loading branch information
nturinski authored Apr 4, 2018
2 parents b1ee080 + 5707473 commit e1ad27a
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 1 deletion.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,11 @@
"type": "integer",
"description": "%azFunc.pickProcessTimeoutDescription%",
"default": 60
},
"azureFunctions.showFuncInstallation": {
"type": "boolean",
"description": "%azFunc.showFuncInstallationDescription%",
"default": true
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@
"azFunc.stopStreamingLogs": "Stop Streaming Logs",
"azFunc.enableRemoteDebugging": "Enable remote debugging, an experimental feature that only supports Java-based Functions Apps.",
"azFunc.deleteProxy": "Delete Proxy",
"azFunc.pickProcessTimeoutDescription": "The timeout (in seconds) to be used when searching for the Azure Functions host process. Since a build is required every time you F5, you may need to adjust this based on how long your build takes."
"azFunc.pickProcessTimeoutDescription": "The timeout (in seconds) to be used when searching for the Azure Functions host process. Since a build is required every time you F5, you may need to adjust this based on how long your build takes.",
"azFunc.showFuncInstallationDescription": "Show a warning to install Azure Functions Core Tools CLI when you create a new project if the CLI is not installed."
}
2 changes: 2 additions & 0 deletions src/commands/createNewProject/createNewProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ProjectCreatorBase } from './IProjectCreator';
import { JavaProjectCreator } from './JavaProjectCreator';
import { JavaScriptProjectCreator } from './JavaScriptProjectCreator';
import { ScriptProjectCreatorBase } from './ScriptProjectCreatorBase';
import { validateFuncCoreToolsInstalled } from './validateFuncCoreToolsInstalled';

export async function createNewProject(
telemetryProperties: TelemetryProperties,
Expand Down Expand Up @@ -65,6 +66,7 @@ export async function createNewProject(
if (templateId) {
await createFunction(telemetryProperties, functionAppPath, templateId, functionName, caseSensitiveFunctionSettings, <ProjectLanguage>language, <ProjectRuntime>runtime);
}
await validateFuncCoreToolsInstalled(ext.ui, ext.outputChannel);

if (openFolder && !workspaceUtil.isFolderOpenInWorkspace(functionAppPath)) {
// If the selected folder is not open in a workspace, open it now. NOTE: This may restart the extension host
Expand Down
103 changes: 103 additions & 0 deletions src/commands/createNewProject/validateFuncCoreToolsInstalled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as opn from 'opn';
import { MessageItem, OutputChannel } from 'vscode';
import { callWithTelemetryAndErrorHandling, DialogResponses, IActionContext, IAzureUserInput } from 'vscode-azureextensionui';
import { Platform } from '../../constants';
import { ext } from '../../extensionVariables';
import { localize } from '../../localize';
import { getFuncExtensionSetting, updateGlobalSetting } from '../../ProjectSettings';
import { cpUtils } from '../../utils/cpUtils';

export async function validateFuncCoreToolsInstalled(ui: IAzureUserInput, outputChannel: OutputChannel): Promise<void> {
let input: MessageItem | undefined;
await callWithTelemetryAndErrorHandling('azureFunctions.validateFuncCoreToolsInstalled', ext.reporter, undefined, async function (this: IActionContext): Promise<void> {
this.suppressErrorDisplay = true;
const settingKey: string = 'showFuncInstallation';
if (getFuncExtensionSetting<boolean>(settingKey)) {
if (!(await funcToolsInstalled()) && (await brewOrNpmInstalled()) && process.platform !== Platform.Linux) {
// https://github.com/Microsoft/vscode-azurefunctions/issues/311
input = await ui.showWarningMessage(localize('installFuncTools', 'You need Azure Functions Core Tools to locally debug your functions. Run {0} now?', getCommandForPlatform()), DialogResponses.yes, DialogResponses.dontWarnAgain, DialogResponses.skipForNow);
if (input === DialogResponses.yes) {
await attemptToInstallLatestFunctionRuntime(ui, outputChannel);
} else if (input === DialogResponses.dontWarnAgain) {
await updateGlobalSetting(settingKey, false);
}
}
}
});
// validate that Func Tools was installed only if user confirmed
if (input === DialogResponses.yes && !(await funcToolsInstalled())) {
if (await ui.showWarningMessage(localize('failedInstallFuncTools', 'The Azure Functions Core Tools installion has failed and will have to be installed manually.'), DialogResponses.learnMore) === DialogResponses.learnMore) {
// tslint:disable-next-line:no-unsafe-any
opn('https://aka.ms/Dqur4e');
}

}
}

async function attemptToInstallLatestFunctionRuntime(ui: IAzureUserInput, outputChannel: OutputChannel): Promise<void> {
switch (process.platform) {
case Platform.Windows:
const v1: MessageItem = { title: 'v1' };
const v2: MessageItem = { title: 'v2' };
const winput: MessageItem = await ui.showWarningMessage(localize('windowsVersion', 'Which version of the runtime do you want to install?'), v1, v2);
if (winput === v1) {
await cpUtils.executeCommand(outputChannel, undefined, 'npm', 'install', '-g', 'azure-functions-core-tools');
} else if (winput === v2) {
await cpUtils.executeCommand(outputChannel, undefined, 'npm', 'install', '-g', 'azure-functions-core-tools@core', '--unsafe-perm', 'true');
}
break;
case Platform.MacOS:
try {
await cpUtils.executeCommand(outputChannel, undefined, 'brew', 'tap', 'azure/functions');
await cpUtils.executeCommand(outputChannel, undefined, 'brew', 'install', 'azure-functions-core-tools');
} catch (error) {
// if brew fails for whatever reason, fall back to npm
await cpUtils.executeCommand(outputChannel, undefined, 'npm', 'install', '-g', 'azure-functions-core-tools@core', '--unsafe-perm', 'true');
}
break;
default:
break;
}
}

function getCommandForPlatform(): string {
switch (process.platform) {
case Platform.MacOS:
return '`brew tap azure/functions && brew install azure-functions-core-tools`';
default:
return '`npm install -g azure-functions-core-tools@core`';
}
}

async function funcToolsInstalled(): Promise<boolean> {
try {
await cpUtils.executeCommand(undefined, undefined, 'func');
return true;
} catch (error) {
return false;
}
}

async function brewOrNpmInstalled(): Promise<boolean> {
switch (process.platform) {
case Platform.MacOS:
try {
await cpUtils.executeCommand(undefined, undefined, 'brew', '--version');
return true;
} catch (error) {
// an error indicates no brew; continue to default, npm case
}
default:
try {
await cpUtils.executeCommand(undefined, undefined, 'npm', '--version');
return true;
} catch (error) {
return false;
}
}
}
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export enum TemplateFilter {
Verified = 'Verified'
}

export enum Platform {
Windows = 'win32',
MacOS = 'darwin',
Linux = 'linux'
}

export const hostFileName: string = 'host.json';
export const localSettingsFileName: string = 'local.settings.json';
export const gitignoreFileName: string = '.gitignore';
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function activate(context: vscode.ExtensionContext): void {
try {
const packageInfo: IPackageInfo = (<(id: string) => IPackageInfo>require)(context.asAbsolutePath('./package.json'));
reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
ext.reporter = reporter;
} catch (error) {
// swallow exceptions so that telemetry doesn't affect user
}
Expand Down
2 changes: 2 additions & 0 deletions src/extensionVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { OutputChannel } from "vscode";
import { AzureTreeDataProvider, IAzureUserInput } from "vscode-azureextensionui";
import TelemetryReporter from "vscode-extension-telemetry";
import { TemplateData } from "./templates/TemplateData";

/**
Expand All @@ -15,4 +16,5 @@ export namespace ext {
export let outputChannel: OutputChannel;
export let ui: IAzureUserInput;
export let templateData: TemplateData;
export let reporter: TelemetryReporter;
}

0 comments on commit e1ad27a

Please sign in to comment.