dependencies messages, no curl on win32, fixes to min Version (#8039)

* checking temp work to move to another branch

* removing freeTds

* dependencies Messages and No curl on Win32

* elipsis instead of ...

* add min version check post install and pr fixes

* removing unnecessary comment

* removing old TODO comment

* fix text messages

* add github toke nto electron download (#8047)

* remove hardcode of kubectl version for download
This commit is contained in:
Arvind Ranasaria
2019-10-27 17:13:12 -07:00
committed by GitHub
parent 833adf3515
commit a7f597c943
8 changed files with 158 additions and 80 deletions

View File

@@ -226,7 +226,6 @@ export const enum ToolStatus {
} }
export interface ITool { export interface ITool {
readonly status: ToolStatus;
readonly isInstalling: boolean; readonly isInstalling: boolean;
readonly name: string; readonly name: string;
readonly displayName: string; readonly displayName: string;
@@ -234,10 +233,12 @@ export interface ITool {
readonly type: ToolType; readonly type: ToolType;
readonly homePage: string; readonly homePage: string;
readonly displayStatus: string; readonly displayStatus: string;
readonly dependencyMessages: string[];
readonly statusDescription: string | undefined; readonly statusDescription: string | undefined;
readonly autoInstallSupported: boolean; readonly autoInstallSupported: boolean;
readonly autoInstallRequired: boolean; readonly autoInstallRequired: boolean;
readonly isNotInstalled: boolean; readonly isNotInstalled: boolean;
readonly isInstalled: boolean;
readonly installationPath: string; readonly installationPath: string;
readonly needsInstallation: boolean; readonly needsInstallation: boolean;
readonly outputChannelName: string; readonly outputChannelName: string;

View File

@@ -157,7 +157,7 @@ export class PlatformService implements IPlatformService {
return await this.runStreamedCommand(command, this._outputChannel, options); return await this.runStreamedCommand(command, this._outputChannel, options);
} }
} catch (error) { } catch (error) {
this._outputChannel.append(localize('platformService.RunCommand.ErroredOut', "\t>>> {0} ... errored out: {1}", command, getErrorMessage(error))); //errors are localized in our code where emitted, other errors are pass through from external components that are not easily localized this._outputChannel.append(localize('platformService.RunCommand.ErroredOut', "\t>>> {0} errored out: {1}", command, getErrorMessage(error))); //errors are localized in our code where emitted, other errors are pass through from external components that are not easily localized
if (!(options && options.ignoreError)) { if (!(options && options.ignoreError)) {
throw error; throw error;
} else { } else {
@@ -232,9 +232,9 @@ export class PlatformService implements IPlatformService {
// Add listeners to print stdout and stderr and exit code // Add listeners to print stdout and stderr and exit code
child.on('exit', (code: number | null, signal: string | null) => { child.on('exit', (code: number | null, signal: string | null) => {
if (code !== null) { if (code !== null) {
outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithCode', " >>> {0} ... exited with code: {1}", command, code)); outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithCode', " >>> {0} exited with code: {1}", command, code));
} else { } else {
outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithSignal', " >>> {0} ... exited with signal: {1}", command, signal)); outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithSignal', " >>> {0} exited with signal: {1}", command, signal));
} }
}); });
child.stdout.on('data', (data: string | Buffer) => { child.stdout.on('data', (data: string | Buffer) => {

View File

@@ -7,7 +7,7 @@ import { SemVer } from 'semver';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { Command, OsType, ToolType } from '../../interfaces'; import { Command, OsType, ToolType } from '../../interfaces';
import { IPlatformService } from '../platformService'; import { IPlatformService } from '../platformService';
import { ToolBase } from './toolBase'; import { ToolBase, dependencyType } from './toolBase';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
const defaultInstallationRoot = '~/.local/bin'; const defaultInstallationRoot = '~/.local/bin';
@@ -72,6 +72,13 @@ export class AzCliTool extends ToolBase {
}; };
} }
protected dependenciesByOsType: Map<OsType, dependencyType[]> = new Map<OsType, dependencyType[]>([
[OsType.linux, []],
[OsType.win32, []],
[OsType.darwin, [dependencyType.Brew]],
[OsType.others, [dependencyType.Curl]]
]);
protected get discoveryCommand(): Command { protected get discoveryCommand(): Command {
return { return {
command: this.discoveryCommandString('az') command: this.discoveryCommandString('az')
@@ -81,66 +88,67 @@ export class AzCliTool extends ToolBase {
const win32InstallationCommands = [ const win32InstallationCommands = [
{ {
comment: localize('resourceDeployment.AziCli.DeletingPreviousAzureCli.msi', "deleting previously downloaded azurecli.msi if one exists ..."), comment: localize('resourceDeployment.AziCli.DeletingPreviousAzureCli.msi', "deleting previously downloaded azurecli.msi if one exists "),
command: `IF EXIST .\\AzureCLI.msi DEL /F .\\AzureCLI.msi` command: `IF EXIST .\\AzureCLI.msi DEL /F .\\AzureCLI.msi`
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.DownloadingAndInstallingAzureCli', "downloading azurecli.msi and installing azure-cli ..."), comment: localize('resourceDeployment.AziCli.DownloadingAndInstallingAzureCli', "downloading azurecli.msi and installing azure-cli "),
command: `powershell -Command "& {(New-Object System.Net.WebClient).DownloadFile('https://aka.ms/installazurecliwindows', 'AzureCLI.msi'); Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /passive /quiet /lvx ADS_AzureCliInstall.log'}"` command: `powershell -Command "& {(New-Object System.Net.WebClient).DownloadFile('https://aka.ms/installazurecliwindows', 'AzureCLI.msi'); Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /passive /quiet /lvx ADS_AzureCliInstall.log'}"`
}, },
{ {
comment: localize('resourceDeployment.AziCli.DisplayingInstallationLog', "displaying the installation log ..."), comment: localize('resourceDeployment.AziCli.DisplayingInstallationLog', "displaying the installation log "),
command: `type AzureCliInstall.log | findstr /i /v /c:"cached product context" | findstr /i /v /c:"has no eligible binary patches" `, command: `type AzureCliInstall.log | findstr /i /v /c:"cached product context" | findstr /i /v /c:"has no eligible binary patches" `,
ignoreError: true ignoreError: true
} }
]; ];
const macOsInstallationCommands = [ const macOsInstallationCommands = [
// try to install brew ourselves
{ {
comment: localize('resourceDeployment.AziCli.UpdatingBrewRepository', "updating your brew repository for azure-cli installation ..."), comment: localize('resourceDeployment.AziCli.UpdatingBrewRepository', "updating your brew repository for azure-cli installation "),
command: 'brew update' command: 'brew update'
}, },
{ {
comment: localize('resourceDeployment.AziCli.InstallingAzureCli', "installing azure-cli ..."), comment: localize('resourceDeployment.AziCli.InstallingAzureCli', "installing azure-cli "),
command: 'brew install azure-cli' command: 'brew install azure-cli'
} }
]; ];
const linuxInstallationCommands = [ const linuxInstallationCommands = [
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.AptGetUpdate', "updating repository information before installing azure-cli ..."), comment: localize('resourceDeployment.AziCli.AptGetUpdate', "updating repository information before installing azure-cli "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.AptGetPackages', "getting packages needed for azure-cli installation ..."), comment: localize('resourceDeployment.AziCli.AptGetPackages', "getting packages needed for azure-cli installation "),
command: 'apt-get install ca-certificates curl apt-transport-https lsb-release gnupg -y' command: 'apt-get install ca-certificates curl apt-transport-https lsb-release gnupg -y'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.DownloadAndInstallingSigningKey', "downloading and installing the signing key for azure-cli ..."), comment: localize('resourceDeployment.AziCli.DownloadAndInstallingSigningKey', "downloading and installing the signing key for azure-cli "),
command: 'curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/microsoft.asc.gpg > /dev/null' command: 'curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/microsoft.asc.gpg > /dev/null'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.AddingAzureCliRepositoryInformation', "adding the azure-cli repository information ..."), comment: localize('resourceDeployment.AziCli.AddingAzureCliRepositoryInformation', "adding the azure-cli repository information "),
command: 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ `lsb_release -cs` main" | tee /etc/apt/sources.list.d/azure-cli.list' command: 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ `lsb_release -cs` main" | tee /etc/apt/sources.list.d/azure-cli.list'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.AptGetUpdateAgain', "updating repository information again for azure-cli ..."), comment: localize('resourceDeployment.AziCli.AptGetUpdateAgain', "updating repository information again for azure-cli "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.InstallingAzureCli', "installing azure-cli ..."), comment: localize('resourceDeployment.AziCli.InstallingAzureCli', "installing azure-cli "),
command: 'apt-get install azure-cli' command: 'apt-get install azure-cli'
} }
]; ];
const defaultInstallationCommands = [ const defaultInstallationCommands = [
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.AziCli.ScriptedInstall', "download and invoking script to install azure-cli ..."), comment: localize('resourceDeployment.AziCli.ScriptedInstall', "download and invoking script to install azure-cli "),
command: 'curl -sL https://aka.ms/InstallAzureCLIDeb | bash' command: 'curl -sL https://aka.ms/InstallAzureCLIDeb | bash'
} }
]; ];

View File

@@ -3,14 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { EOL } from 'os'; import { EOL } from 'os';
import * as vscode from 'vscode';
import * as path from 'path'; import * as path from 'path';
import { SemVer } from 'semver'; import { SemVer } from 'semver';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { azdataPipInstallArgsKey, AzdataPipInstallUriKey, DeploymentConfigurationKey } from '../../constants';
import { Command, OsType, ToolType } from '../../interfaces'; import { Command, OsType, ToolType } from '../../interfaces';
import { IPlatformService } from '../platformService'; import { IPlatformService } from '../platformService';
import { ToolBase } from './toolBase'; import { dependencyType, ToolBase } from './toolBase';
import { DeploymentConfigurationKey, AzdataPipInstallUriKey, azdataPipInstallArgsKey } from '../../constants';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -91,11 +91,11 @@ export class AzdataTool extends ToolBase {
private get defaultInstallationCommands(): Command[] { private get defaultInstallationCommands(): Command[] {
return [ return [
{ {
comment: localize('resourceDeployment.Azdata.InstallUpdatePythonRequestsPackage', "installing/updating to latest version of requests python package azdata ..."), comment: localize('resourceDeployment.Azdata.InstallUpdatePythonRequestsPackage', "installing/updating to latest version of requests python package azdata "),
command: `pip3 install -U requests` command: `pip3 install -U requests`
}, },
{ {
comment: localize('resourceDeployment.Azdata.InstallingAzdata', "installing azdata ..."), comment: localize('resourceDeployment.Azdata.InstallingAzdata', "installing azdata "),
command: `pip3 install -r ${this.azdataInstallUri} ${this.azdataInstallAdditionalArgs} --quiet --user` command: `pip3 install -r ${this.azdataInstallUri} ${this.azdataInstallAdditionalArgs} --quiet --user`
} }
]; ];
@@ -112,38 +112,45 @@ export class AzdataTool extends ToolBase {
private get azdataInstallAdditionalArgs(): string { private get azdataInstallAdditionalArgs(): string {
return vscode.workspace.getConfiguration(DeploymentConfigurationKey)[azdataPipInstallArgsKey]; return vscode.workspace.getConfiguration(DeploymentConfigurationKey)[azdataPipInstallArgsKey];
} }
protected dependenciesByOsType: Map<OsType, dependencyType[]> = new Map<OsType, dependencyType[]>([
[OsType.linux, [dependencyType.PythonAndPip3]],
[OsType.win32, [dependencyType.PythonAndPip3]],
[OsType.darwin, [dependencyType.PythonAndPip3]],
[OsType.others, [dependencyType.PythonAndPip3]]
]);
} }
/* /*
const linuxInstallationCommands = [ const linuxInstallationCommands = [
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.AptGetUpdate', "updating repository information ..."), comment: localize('resourceDeployment.Azdata.AptGetUpdate', "updating repository information "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.AptGetPackages', "getting packages needed for azdata installation ..."), comment: localize('resourceDeployment.Azdata.AptGetPackages', "getting packages needed for azdata installation "),
command: 'apt-get install gnupg ca-certificates curl apt-transport-https lsb-release -y' command: 'apt-get install gnupg ca-certificates curl apt-transport-https lsb-release -y'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.DownloadAndInstallingSigningKey', "downloading and installing the signing key for azdata ..."), comment: localize('resourceDeployment.Azdata.DownloadAndInstallingSigningKey', "downloading and installing the signing key for azdata "),
command: 'wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add -' command: 'wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add -'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.AddingAzureCliRepositoryInformation', "adding the azdata repository information ..."), comment: localize('resourceDeployment.Azdata.AddingAzureCliRepositoryInformation', "adding the azdata repository information "),
command: 'add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-preview.list)"' command: 'add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-preview.list)"'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.AptGetUpdate', "updating repository information ..."), comment: localize('resourceDeployment.Azdata.AptGetUpdate', "updating repository information "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Azdata.InstallingAzdata', "installing azdata ..."), comment: localize('resourceDeployment.Azdata.InstallingAzdata', "installing azdata "),
command: 'apt-get install -y azdata-cli' command: 'apt-get install -y azdata-cli'
} }
]; ];

View File

@@ -7,7 +7,7 @@ import { Command, ToolType, OsType } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { SemVer } from 'semver'; import { SemVer } from 'semver';
import { IPlatformService } from '../platformService'; import { IPlatformService } from '../platformService';
import { ToolBase } from './toolBase'; import { ToolBase, dependencyType } from './toolBase';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -75,86 +75,92 @@ export class KubeCtlTool extends ToolBase {
[OsType.darwin, macOsInstallationCommands], [OsType.darwin, macOsInstallationCommands],
[OsType.others, defaultInstallationCommands] [OsType.others, defaultInstallationCommands]
]); ]);
protected dependenciesByOsType: Map<OsType, dependencyType[]> = new Map<OsType, dependencyType[]>([
[OsType.linux, []],
[OsType.win32, []],
[OsType.darwin, [dependencyType.Brew]],
[OsType.others, [dependencyType.Curl]]
]);
} }
const macOsInstallationCommands = [ const macOsInstallationCommands = [
{ {
comment: localize('resourceDeployment.Kubectl.UpdatingBrewRepository', "updating your brew repository for kubectl installation ..."), comment: localize('resourceDeployment.Kubectl.UpdatingBrewRepository', "updating your brew repository for kubectl installation "),
command: 'brew update' command: 'brew update'
}, },
{ {
comment: localize('resourceDeployment.Kubectl.InstallingKubeCtl', "installing kubectl ..."), comment: localize('resourceDeployment.Kubectl.InstallingKubeCtl', "installing kubectl "),
command: 'brew install kubectl' command: 'brew install kubectl'
} }
]; ];
const linuxInstallationCommands = [ const linuxInstallationCommands = [
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.AptGetUpdate', "updating repository information ..."), comment: localize('resourceDeployment.Kubectl.AptGetUpdate', "updating repository information "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.AptGetPackages', "getting packages needed for kubectl installation ..."), comment: localize('resourceDeployment.Kubectl.AptGetPackages', "getting packages needed for kubectl installation "),
command: 'apt-get install -y apt-transport-https' command: 'apt-get install -y apt-transport-https'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.DownloadAndInstallingSigningKey', "downloading and installing the signing key for kubectl ..."), comment: localize('resourceDeployment.Kubectl.DownloadAndInstallingSigningKey', "downloading and installing the signing key for kubectl "),
command: 'curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -' command: 'curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.AddingKubectlRepositoryInformation', "adding the kubectl repository information ..."), comment: localize('resourceDeployment.Kubectl.AddingKubectlRepositoryInformation', "adding the kubectl repository information "),
command: 'echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list' command: 'echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.AptGetUpdate', "updating repository information ..."), comment: localize('resourceDeployment.Kubectl.AptGetUpdate', "updating repository information "),
command: 'apt-get update' command: 'apt-get update'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.InstallingKubectl', "installing kubectl ..."), comment: localize('resourceDeployment.Kubectl.InstallingKubectl', "installing kubectl "),
command: 'apt-get install -y kubectl' command: 'apt-get install -y kubectl'
} }
]; ];
// TODO: Remove dependency on curl on Win32 and use powershell Invoke-WebRequest instead
const win32InstallationCommands = [ const win32InstallationCommands = [
{ {
comment: localize('resourceDeployment.Kubectl.DeletePreviousDownloadedKubectl.exe', "deleting previously downloaded kubectl.exe if one exists ..."), comment: localize('resourceDeployment.Kubectl.DeletePreviousDownloadedKubectl.exe', "deleting previously downloaded kubectl.exe if one exists "),
command: `IF EXIST .\kubectl.exe DEL /F .\kubectl.exe`, command: 'IF EXIST .\\kubectl.exe DEL /F .\\kubectl.exe',
}, },
{ {
comment: localize('resourceDeployment.Kubectl.DownloadingAndInstallingKubectl', "downloading and installing the latest kubectl.exe ..."), comment: localize('resourceDeployment.Kubectl.DownloadingAndInstallingKubectl', "downloading and installing the latest kubectl.exe "),
command: `for /f %i in ('curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt') do curl -LO https://storage.googleapis.com/kubernetes-release/release/%i/bin/windows/amd64/kubectl.exe` command: `powershell -Command "& {$WebClient = New-Object System.Net.WebClient; $Version=$WebClient.DownloadString('https://storage.googleapis.com/kubernetes-release/release/stable.txt').Trim();Write-Output \\\"KubeCtl Version=$Version\\\";$Url=\\\"https://storage.googleapis.com/kubernetes-release/release/$Version/bin/windows/amd64/kubectl.exe\\\"; Write-Output \\\"Downloading file: $Url\\\"; $WebClient.DownloadFile($Url, 'kubectl.exe')}"`
} }
]; ];
const defaultInstallationCommands = [ const defaultInstallationCommands = [
{ {
comment: localize('resourceDeployment.Kubectl.DeletePreviousDownloadedKubectl', "deleting previously downloaded kubectl if one exists ..."), comment: localize('resourceDeployment.Kubectl.DeletePreviousDownloadedKubectl', "deleting previously downloaded kubectl if one exists "),
command: `[ -e ./kubectl ] && rm -f ./kubectl`, command: `[ -e ./kubectl ] && rm -f ./kubectl`,
}, },
{ {
comment: localize('resourceDeployment.Kubectl.DownloadingKubectl', "downloading the latest kubectl release ..."), comment: localize('resourceDeployment.Kubectl.DownloadingKubectl', "downloading the latest kubectl release "),
command: 'curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl' command: 'curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl'
}, },
{ {
comment: localize('resourceDeployment.Kubectl.MakingExecutable', "making kubectl executable ..."), comment: localize('resourceDeployment.Kubectl.MakingExecutable', "making kubectl executable "),
command: 'chmod +x ./kubectl', command: 'chmod +x ./kubectl',
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.CleaningUpOldBackups', "cleaning up any previously backed up version in the install location if they exist ..."), comment: localize('resourceDeployment.Kubectl.CleaningUpOldBackups', "cleaning up any previously backed up version in the install location if they exist "),
command: `[ -e /usr/local/bin/kubectl] && [ -e /usr/local/bin/kubectl_movedByADS ] && rm -f /usr/local/bin/kubectl_movedByADS` command: '[ -e /usr/local/bin/kubectl] && [ -e /usr/local/bin/kubectl_movedByADS ] && rm -f /usr/local/bin/kubectl_movedByADS'
}, },
{ {
sudo: true, sudo: true,
comment: localize('resourceDeployment.Kubectl.BackupCurrentBinary', "backing up any existing kubectl in the install location ..."), comment: localize('resourceDeployment.Kubectl.BackupCurrentBinary', "backing up any existing kubectl in the install location "),
command: `[ -e /usr/local/bin/kubectl ] && mv /usr/local/bin/kubectl /usr/local/bin/kubectl_movedByADS` command: '[ -e /usr/local/bin/kubectl ] && mv /usr/local/bin/kubectl /usr/local/bin/kubectl_movedByADS'
}, },
{ {
comment: localize('resourceDeployment.Kubectl.MoveToSystemPath', "moving kubectl into the install location in the PATH ..."), comment: localize('resourceDeployment.Kubectl.MoveToSystemPath', "moving kubectl into the install location in the PATH "),
sudo: true, sudo: true,
command: 'mv ./kubectl /usr/local/bin/kubectl' command: 'mv ./kubectl /usr/local/bin/kubectl'
} }

View File

@@ -14,7 +14,7 @@ import { IPlatformService } from '../platformService';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
const toolStatusNotInstalled: string = localize('deploymentDialog.ToolStatus.NotInstalled', "Not Installed"); const toolStatusNotInstalled: string = localize('deploymentDialog.ToolStatus.NotInstalled', "Not Installed");
const toolStatusInstalled: string = localize('deploymentDialog.ToolStatus.Installed', "Installed"); const toolStatusInstalled: string = localize('deploymentDialog.ToolStatus.Installed', "Installed");
const toolStatusInstalling: string = localize('deploymentDialog.ToolStatus.Installing', "Installing"); const toolStatusInstalling: string = localize('deploymentDialog.ToolStatus.Installing', "Installing");
const toolStatusError: string = localize('deploymentDialog.ToolStatus.Error', "Error"); const toolStatusError: string = localize('deploymentDialog.ToolStatus.Error', "Error");
const toolStatusFailed: string = localize('deploymentDialog.ToolStatus.Failed', "Failed"); const toolStatusFailed: string = localize('deploymentDialog.ToolStatus.Failed', "Failed");
@@ -26,6 +26,22 @@ const toolStatusLocalized: Map<ToolStatus, string> = new Map<ToolStatus, string>
[ToolStatus.Failed, toolStatusFailed] [ToolStatus.Failed, toolStatusFailed]
]); ]);
export const enum dependencyType {
PythonAndPip3 = 'PythonAndPip3',
Brew = 'Brew',
Curl = 'Curl'
}
const pythonAndPip3Localized = localize('deploymentDialog.ToolInformationalMessage.PythonAndPip3', "• azdata installation needs python3 and pip3 to be pre-installed before necessary tools can be deployed");
const brewLocalized = localize('deploymentDialog.ToolInformationalMessage.Brew', "• brew is needed for deployment of the tools and needs to be pre-installed before necessary tools can be deployed");
const curlLocalized = localize('deploymentDialog.ToolInformationalMessage.Curl', "• curl is needed for installation and needs to be pre-installed before necessary tools can be deployed");
export const messageByDependencyType: Map<dependencyType, string> = new Map<dependencyType, string>([
[dependencyType.PythonAndPip3, pythonAndPip3Localized],
[dependencyType.Brew, brewLocalized],
[dependencyType.Curl, curlLocalized]
]);
export abstract class ToolBase implements ITool { export abstract class ToolBase implements ITool {
constructor(private _platformService: IPlatformService) { constructor(private _platformService: IPlatformService) {
this._osType = this._platformService.osType(); this._osType = this._platformService.osType();
@@ -38,13 +54,22 @@ export abstract class ToolBase implements ITool {
abstract homePage: string; abstract homePage: string;
abstract autoInstallSupported: boolean; abstract autoInstallSupported: boolean;
protected abstract readonly allInstallationCommands: Map<OsType, Command[]>; protected abstract readonly allInstallationCommands: Map<OsType, Command[]>;
protected readonly dependenciesByOsType: Map<OsType, dependencyType[]> = new Map<OsType, dependencyType[]>();
protected abstract getVersionFromOutput(output: string): SemVer | undefined; protected abstract getVersionFromOutput(output: string): SemVer | undefined;
protected readonly _onDidUpdateData = new vscode.EventEmitter<ITool>(); protected readonly _onDidUpdateData = new vscode.EventEmitter<ITool>();
protected readonly uninstallCommand?: string; protected readonly uninstallCommand?: string;
protected abstract readonly versionCommand: Command; protected abstract readonly versionCommand: Command;
public get dependencyMessages(): string[] {
return (this.dependenciesByOsType.get(this.osType) || []).map((msgType: dependencyType) => messageByDependencyType.get(msgType)!);
}
protected async getInstallationPath(): Promise<string | undefined> {
return undefined;
}
protected abstract readonly discoveryCommand: Command; protected abstract readonly discoveryCommand: Command;
protected async getSearchPaths(): Promise<string[]> { protected async getSearchPaths(): Promise<string[]> {
@@ -63,11 +88,11 @@ export abstract class ToolBase implements ITool {
return this._onDidUpdateData.event; return this._onDidUpdateData.event;
} }
get status(): ToolStatus { protected get status(): ToolStatus {
return this._status; return this._status;
} }
set status(value: ToolStatus) { protected set status(value: ToolStatus) {
this._status = value; this._status = value;
this._onDidUpdateData.fire(this); this._onDidUpdateData.fire(this);
} }
@@ -84,6 +109,10 @@ export abstract class ToolBase implements ITool {
return this.status === ToolStatus.NotInstalled; return this.status === ToolStatus.NotInstalled;
} }
public get isInstalled(): boolean {
return this.status === ToolStatus.Installed;
}
public get isInstalling(): boolean { public get isInstalling(): boolean {
return this.status === ToolStatus.Installing; return this.status === ToolStatus.Installing;
} }
@@ -154,6 +183,7 @@ export abstract class ToolBase implements ITool {
} }
public async install(): Promise<void> { public async install(): Promise<void> {
this._statusDescription = '';
try { try {
this.status = ToolStatus.Installing; this.status = ToolStatus.Installing;
await this.installCore(); await this.installCore();
@@ -221,6 +251,7 @@ export abstract class ToolBase implements ITool {
} }
private async updateVersionAndGetStatus(): Promise<ToolStatus> { private async updateVersionAndGetStatus(): Promise<ToolStatus> {
this._statusDescription = '';
const commandOutput = await this._platformService.runCommand( const commandOutput = await this._platformService.runCommand(
this.versionCommand.command, this.versionCommand.command,
{ {
@@ -271,10 +302,7 @@ export abstract class ToolBase implements ITool {
} }
isSameOrNewerThan(version: string): boolean { isSameOrNewerThan(version: string): boolean {
const currentVersion = new SemVer(this.fullVersion!); return this._version ? compare(this._version, new SemVer(version)) >= 0 : false;
const requiredVersion = new SemVer(version);
return compare(currentVersion, requiredVersion) >= 0;
} }
private _storagePathEnsured: boolean = false; private _storagePathEnsured: boolean = false;

View File

@@ -14,13 +14,20 @@ export interface IToolsService {
} }
export class ToolsService implements IToolsService { export class ToolsService implements IToolsService {
private supportedTools: ITool[]; private supportedTools: Map<string, ITool>;
constructor(private _platformService: IPlatformService) { constructor(private _platformService: IPlatformService) {
this.supportedTools = [new DockerTool(this._platformService), new AzCliTool(this._platformService), new AzdataTool(this._platformService), new KubeCtlTool(this._platformService)]; this.supportedTools = new Map<string, ITool>(
[
new DockerTool(this._platformService),
new AzCliTool(this._platformService),
new AzdataTool(this._platformService),
new KubeCtlTool(this._platformService)
].map<[string, ITool]>((tool: ITool) => [tool.name, tool])
);
} }
getToolByName(toolName: string): ITool | undefined { getToolByName(toolName: string): ITool | undefined {
return this.supportedTools.find(t => t.name === toolName); return this.supportedTools.get(toolName);
} }
} }

View File

@@ -5,7 +5,7 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { EOL } from 'os'; import { EOL } from 'os';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { AgreementInfo, DeploymentProvider, ITool, ResourceType, ToolStatus } from '../interfaces'; import { AgreementInfo, DeploymentProvider, ITool, ResourceType } from '../interfaces';
import { IResourceTypeService } from '../services/resourceTypeService'; import { IResourceTypeService } from '../services/resourceTypeService';
import { IToolsService } from '../services/toolsService'; import { IToolsService } from '../services/toolsService';
import { getErrorMessage, setEnvironmentVariablesForInstallPaths } from '../utils'; import { getErrorMessage, setEnvironmentVariablesForInstallPaths } from '../utils';
@@ -70,7 +70,7 @@ export class ResourceTypePickerDialog extends DialogBase {
this._agreementContainer = view.modelBuilder.divContainer().component(); this._agreementContainer = view.modelBuilder.divContainer().component();
const toolColumn: azdata.TableColumn = { const toolColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolNameColumnHeader', "Tool"), value: localize('deploymentDialog.toolNameColumnHeader', "Tool"),
width: 150 width: 70
}; };
const descriptionColumn: azdata.TableColumn = { const descriptionColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolDescriptionColumnHeader', "Description"), value: localize('deploymentDialog.toolDescriptionColumnHeader', "Description"),
@@ -78,15 +78,15 @@ export class ResourceTypePickerDialog extends DialogBase {
}; };
const installStatusColumn: azdata.TableColumn = { const installStatusColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolStatusColumnHeader', "Status"), value: localize('deploymentDialog.toolStatusColumnHeader', "Status"),
width: 100 width: 70
}; };
const versionColumn: azdata.TableColumn = { const versionColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolVersionColumnHeader', "Version"), value: localize('deploymentDialog.toolVersionColumnHeader', "Installed Version"),
width: 100 width: 90
}; };
const minVersionColumn: azdata.TableColumn = { const minVersionColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolMinimumVersionColumnHeader', "Minimum Version"), value: localize('deploymentDialog.toolMinimumVersionColumnHeader', "Required Version"),
width: 100 width: 90
}; };
this._toolsTable = view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({ this._toolsTable = view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({
@@ -219,8 +219,9 @@ export class ResourceTypePickerDialog extends DialogBase {
}); });
this._toolsLoadingComponent.loading = true; this._toolsLoadingComponent.loading = true;
this._dialogObject.okButton.enabled = false; this._dialogObject.okButton.enabled = false;
Promise.all(
Promise.all(this._tools.map(tool => tool.loadInformation())).then(async () => { this._tools.map(tool => tool.loadInformation())
).then(async () => {
// If the local timestamp does not match the class level timestamp, it means user has changed options, ignore the results // If the local timestamp does not match the class level timestamp, it means user has changed options, ignore the results
if (this.toolRefreshTimestamp !== currentRefreshTimestamp) { if (this.toolRefreshTimestamp !== currentRefreshTimestamp) {
return; return;
@@ -239,10 +240,9 @@ export class ResourceTypePickerDialog extends DialogBase {
if (tool.statusDescription !== undefined) { if (tool.statusDescription !== undefined) {
console.warn(localize('deploymentDialog.DetailToolStatusDescription', "Additional status information for tool: '{0}' [ {1} ]. {2}", tool.name, tool.homePage, tool.statusDescription)); console.warn(localize('deploymentDialog.DetailToolStatusDescription', "Additional status information for tool: '{0}' [ {1} ]. {2}", tool.name, tool.homePage, tool.statusDescription));
} }
} else if (tool.status === ToolStatus.Installed && toolReq.version && !tool.isSameOrNewerThan(toolReq.version)) { } else if (tool.isInstalled && toolReq.version && !tool.isSameOrNewerThan(toolReq.version)) {
minVersionCheckFailed = true; minVersionCheckFailed = true;
messages.push(localize('deploymentDialog.ToolDoesNotMeetVersionRequirement', "'{0}' [ {1} ] does not meet the minimum version requirement, please uninstall it and restart Azure Data Studio.", tool.displayName, tool.homePage)); messages.push(localize('deploymentDialog.ToolDoesNotMeetVersionRequirement', "'{0}' [ {1} ] does not meet the minimum version requirement, please uninstall it and restart Azure Data Studio.", tool.displayName, tool.homePage));
} }
autoInstallRequired = autoInstallRequired || tool.autoInstallRequired; autoInstallRequired = autoInstallRequired || tool.autoInstallRequired;
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', toolReq.version || '']; return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', toolReq.version || ''];
@@ -260,11 +260,22 @@ export class ResourceTypePickerDialog extends DialogBase {
description: messages.join(EOL) description: messages.join(EOL)
}; };
} else if (autoInstallRequired) { } else if (autoInstallRequired) {
let infoText: string[] = [localize('deploymentDialog.InstallToolsHint', "Some required tools are not installed, you can click the \"{0}\" button to install them.", this._installToolButton.label)];
const informationalMessagesArray = this._tools.reduce<string[]>((returnArray, currentTool) => {
if (currentTool.needsInstallation) {
returnArray.push(...currentTool.dependencyMessages);
}
return returnArray;
}, /* initial Value of return array*/[]);
const informationalMessagesSet: Set<string> = new Set<string>(informationalMessagesArray);
if (informationalMessagesSet.size > 0) {
infoText.push(...informationalMessagesSet.values());
}
// we don't have scenarios that have mixed type of tools // we don't have scenarios that have mixed type of tools
// either we don't support auto install: docker, or we support auto install for all required tools // either we don't support auto install: docker, or we support auto install for all required tools
this._dialogObject.message = { this._dialogObject.message = {
level: azdata.window.MessageLevel.Warning, level: azdata.window.MessageLevel.Warning,
text: localize('deploymentDialog.InstallToolsHint', "Some required tools are not installed, you can click the \"{0}\" button to install them.", this._installToolButton.label) text: infoText.join(EOL)
}; };
} }
this._toolsLoadingComponent.loading = false; this._toolsLoadingComponent.loading = false;
@@ -302,7 +313,7 @@ export class ResourceTypePickerDialog extends DialogBase {
this.resourceTypeService.startDeployment(this.getCurrentProvider()); this.resourceTypeService.startDeployment(this.getCurrentProvider());
} }
public updateToolsDisplayTableData(tool: ITool) { protected updateToolsDisplayTableData(tool: ITool) {
this._toolsTable.data = this._toolsTable.data.map(rowData => { this._toolsTable.data = this._toolsTable.data.map(rowData => {
if (rowData[0] === tool.displayName) { if (rowData[0] === tool.displayName) {
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', rowData[4]]; return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', rowData[4]];
@@ -323,16 +334,26 @@ export class ResourceTypePickerDialog extends DialogBase {
private async installTools(): Promise<void> { private async installTools(): Promise<void> {
this._installToolButton.enabled = false; this._installToolButton.enabled = false;
let i: number = 0; let tool: ITool;
try { try {
for (; i < this._tools.length; i++) { const toolRequirements = this.getCurrentProvider().requiredTools;
if (this._tools[i].needsInstallation) { for (let i: number = 0; i < toolRequirements.length; i++) {
const toolReq = toolRequirements[i];
tool = this.toolsService.getToolByName(toolReq.name)!;
if (tool.needsInstallation) {
// Update the informational message // Update the informational message
this._dialogObject.message = { this._dialogObject.message = {
level: azdata.window.MessageLevel.Information, level: azdata.window.MessageLevel.Information,
text: localize('deploymentDialog.InstallingTool', "Required tool '{0}' [ {1} ] is being installed now.", this._tools[i].displayName, this._tools[i].homePage) text: localize('deploymentDialog.InstallingTool', "Required tool '{0}' [ {1} ] is being installed now.", tool.displayName, tool.homePage)
}; };
await this._tools[i].install(); await this._tools[i].install();
if (tool.isInstalled && toolReq.version && !tool.isSameOrNewerThan(toolReq.version)) {
throw new Error(
localize('deploymentDialog.ToolDoesNotMeetVersionRequirement', "'{0}' [ {1} ] does not meet the minimum version requirement, please uninstall it and restart Azure Data Studio.",
tool.displayName, tool.homePage
)
);
}
} }
} }
// Update the informational message // Update the informational message
@@ -342,7 +363,7 @@ export class ResourceTypePickerDialog extends DialogBase {
}; };
this._dialogObject.okButton.enabled = true; this._dialogObject.okButton.enabled = true;
} catch (error) { } catch (error) {
const errorMessage = this._tools[i].statusDescription || getErrorMessage(error); const errorMessage = tool!.statusDescription || getErrorMessage(error);
if (errorMessage) { if (errorMessage) {
// Let the tooltip status show the errorMessage just shown so that last status is visible even after showError dialogue has been dismissed. // Let the tooltip status show the errorMessage just shown so that last status is visible even after showError dialogue has been dismissed.
this._dialogObject.message = { this._dialogObject.message = {
@@ -350,7 +371,7 @@ export class ResourceTypePickerDialog extends DialogBase {
text: errorMessage text: errorMessage
}; };
} }
this._tools[i].showOutputChannel(/*preserverFocus*/false); tool!.showOutputChannel(/*preserverFocus*/false);
} }
} }
} }