mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 17:23:51 -05:00
Feature/mssql-big-data-cluster (#4107)
* Adding kubernetes installer. * Adding variety of kubectl support and integrating into the kubeconfig target cluster page. * Addressing PR comments, refactored utility file locations and added missing license headers.
This commit is contained in:
@@ -23,6 +23,56 @@
|
||||
"Microsoft.mssql"
|
||||
],
|
||||
"contributes": {
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Kubernetes configuration",
|
||||
"properties": {
|
||||
"mssql-bdc": {
|
||||
"type": "object",
|
||||
"description": "Kubernetes configuration",
|
||||
"properties": {
|
||||
"mssql-bdc.kubectl-path": {
|
||||
"type": "string",
|
||||
"description": "File path to a kubectl binary."
|
||||
},
|
||||
"mssql-bdc.kubectl-path.windows": {
|
||||
"type": "string",
|
||||
"description": "File path to a kubectl binary."
|
||||
},
|
||||
"mssql-bdc.kubectl-path.mac": {
|
||||
"type": "string",
|
||||
"description": "File path to a kubectl binary."
|
||||
},
|
||||
"mssql-bdc.kubectl-path.linux": {
|
||||
"type": "string",
|
||||
"description": "File path to a kubectl binary."
|
||||
},
|
||||
"mssql-bdc.kubeconfig": {
|
||||
"type": "string",
|
||||
"description": "File path to the kubeconfig file."
|
||||
},
|
||||
"mssql-bdc.knownKubeconfigs": {
|
||||
"type": "array",
|
||||
"description": "File paths to kubeconfig files from which you can select."
|
||||
},
|
||||
"mssql-bdc.outputFormat": {
|
||||
"enum": [
|
||||
"json",
|
||||
"yaml"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Output format for Kubernetes specs. One of 'json' or 'yaml' (default)."
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"mssql-bdc.namespace": "",
|
||||
"mssql-bdc.kubectl-path": "",
|
||||
"mssql-bdc.kubeconfig": "",
|
||||
"mssql-bdc.knownKubeconfigs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "mssql.cluster.create",
|
||||
@@ -32,7 +82,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
"vscode-nls": "^3.2.1",
|
||||
"download": "^6.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
|
||||
121
extensions/big-data-cluster/src/config/config.ts
Normal file
121
extensions/big-data-cluster/src/config/config.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Host } from '../kubectl/host';
|
||||
import { Shell, Platform } from '../utility/shell';
|
||||
|
||||
const EXTENSION_CONFIG_KEY = "mssql-bdc";
|
||||
const KUBECONFIG_PATH_KEY = "mssql-bdc.kubeconfig";
|
||||
const KNOWN_KUBECONFIGS_KEY = "mssql-bdc.knownKubeconfigs";
|
||||
|
||||
export async function addPathToConfig(configKey: string, value: string): Promise<void> {
|
||||
await setConfigValue(configKey, value);
|
||||
}
|
||||
|
||||
async function setConfigValue(configKey: string, value: any): Promise<void> {
|
||||
await atAllConfigScopes(addValueToConfigAtScope, configKey, value);
|
||||
}
|
||||
|
||||
async function addValueToConfigAtScope(configKey: string, value: any, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean): Promise<void> {
|
||||
if (!createIfNotExist) {
|
||||
if (!valueAtScope || !(valueAtScope[configKey])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let newValue: any = {};
|
||||
if (valueAtScope) {
|
||||
newValue = Object.assign({}, valueAtScope);
|
||||
}
|
||||
newValue[configKey] = value;
|
||||
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
|
||||
}
|
||||
|
||||
async function addValueToConfigArray(configKey: string, value: string): Promise<void> {
|
||||
await atAllConfigScopes(addValueToConfigArrayAtScope, configKey, value);
|
||||
}
|
||||
|
||||
async function addValueToConfigArrayAtScope(configKey: string, value: string, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean): Promise<void> {
|
||||
if (!createIfNotExist) {
|
||||
if (!valueAtScope || !(valueAtScope[configKey])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let newValue: any = {};
|
||||
if (valueAtScope) {
|
||||
newValue = Object.assign({}, valueAtScope);
|
||||
}
|
||||
const arrayEntry: string[] = newValue[configKey] || [];
|
||||
arrayEntry.push(value);
|
||||
newValue[configKey] = arrayEntry;
|
||||
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
|
||||
}
|
||||
|
||||
type ConfigUpdater<T> = (configKey: string, value: T, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean) => Promise<void>;
|
||||
|
||||
async function atAllConfigScopes<T>(fn: ConfigUpdater<T>, configKey: string, value: T): Promise<void> {
|
||||
const config = vscode.workspace.getConfiguration().inspect(EXTENSION_CONFIG_KEY)!;
|
||||
await fn(configKey, value, vscode.ConfigurationTarget.Global, config.globalValue, true);
|
||||
await fn(configKey, value, vscode.ConfigurationTarget.Workspace, config.workspaceValue, false);
|
||||
await fn(configKey, value, vscode.ConfigurationTarget.WorkspaceFolder, config.workspaceFolderValue, false);
|
||||
}
|
||||
|
||||
// Functions for working with the list of known kubeconfigs
|
||||
|
||||
export function getKnownKubeconfigs(): string[] {
|
||||
const kkcConfig = vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KNOWN_KUBECONFIGS_KEY];
|
||||
if (!kkcConfig || !kkcConfig.length) {
|
||||
return [];
|
||||
}
|
||||
return kkcConfig as string[];
|
||||
}
|
||||
|
||||
export async function addKnownKubeconfig(kubeconfigPath: string) {
|
||||
await addValueToConfigArray(KNOWN_KUBECONFIGS_KEY, kubeconfigPath);
|
||||
}
|
||||
|
||||
// Functions for working with the active kubeconfig setting
|
||||
|
||||
export async function setActiveKubeconfig(kubeconfig: string): Promise<void> {
|
||||
await addPathToConfig(KUBECONFIG_PATH_KEY, kubeconfig);
|
||||
}
|
||||
|
||||
export function getActiveKubeconfig(): string {
|
||||
return vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KUBECONFIG_PATH_KEY];
|
||||
}
|
||||
|
||||
// Functions for working with tool paths
|
||||
|
||||
export function getToolPath(host: Host, shell: Shell, tool: string): string | undefined {
|
||||
const baseKey = toolPathBaseKey(tool);
|
||||
return getPathSetting(host, shell, baseKey);
|
||||
}
|
||||
|
||||
function getPathSetting(host: Host, shell: Shell, baseKey: string): string | undefined {
|
||||
const os = shell.platform();
|
||||
const osOverridePath = host.getConfiguration(EXTENSION_CONFIG_KEY)[osOverrideKey(os, baseKey)];
|
||||
return osOverridePath || host.getConfiguration(EXTENSION_CONFIG_KEY)[baseKey];
|
||||
}
|
||||
|
||||
export function toolPathBaseKey(tool: string): string {
|
||||
return `mssql-bdc.${tool}-path`;
|
||||
}
|
||||
|
||||
function osOverrideKey(os: Platform, baseKey: string): string {
|
||||
const osKey = osKeyString(os);
|
||||
return osKey ? `${baseKey}.${osKey}` : baseKey; // The 'else' clause should never happen so don't worry that this would result in double-checking a missing base key
|
||||
}
|
||||
|
||||
function osKeyString(os: Platform): string | null {
|
||||
switch (os) {
|
||||
case Platform.Windows: return 'windows';
|
||||
case Platform.MacOS: return 'mac';
|
||||
case Platform.Linux: return 'linux';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
45
extensions/big-data-cluster/src/installer/download.ts
Normal file
45
extensions/big-data-cluster/src/installer/download.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as stream from 'stream';
|
||||
import * as tmp from 'tmp';
|
||||
|
||||
import { succeeded, Errorable } from '../interfaces';
|
||||
|
||||
type DownloadFunc =
|
||||
(url: string, destination?: string, options?: any)
|
||||
=> Promise<Buffer> & stream.Duplex; // Stream has additional events - see https://www.npmjs.com/package/download
|
||||
|
||||
let download: DownloadFunc;
|
||||
|
||||
function ensureDownloadFunc() {
|
||||
if (!download) {
|
||||
const home = process.env['HOME'];
|
||||
download = require('download');
|
||||
if (home) {
|
||||
process.env['HOME'] = home;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function toTempFile(sourceUrl: string): Promise<Errorable<string>> {
|
||||
const tempFileObj = tmp.fileSync({ prefix: "mssql-bdc-autoinstall-" });
|
||||
const downloadResult = await to(sourceUrl, tempFileObj.name);
|
||||
if (succeeded(downloadResult)) {
|
||||
return { succeeded: true, result: tempFileObj.name };
|
||||
}
|
||||
return { succeeded: false, error: downloadResult.error };
|
||||
}
|
||||
|
||||
export async function to(sourceUrl: string, destinationFile: string): Promise<Errorable<null>> {
|
||||
ensureDownloadFunc();
|
||||
try {
|
||||
await download(sourceUrl, path.dirname(destinationFile), { filename: path.basename(destinationFile) });
|
||||
return { succeeded: true, result: null };
|
||||
} catch (e) {
|
||||
return { succeeded: false, error: [e.message] };
|
||||
}
|
||||
}
|
||||
69
extensions/big-data-cluster/src/installer/installer.ts
Normal file
69
extensions/big-data-cluster/src/installer/installer.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as download from './download';
|
||||
import * as fs from 'fs';
|
||||
import mkdirp = require('mkdirp');
|
||||
import * as path from 'path';
|
||||
import { Shell, Platform } from '../utility/shell';
|
||||
import { Errorable, failed } from '../interfaces';
|
||||
import { addPathToConfig, toolPathBaseKey } from '../config/config';
|
||||
|
||||
export async function installKubectl(shell: Shell): Promise<Errorable<null>> {
|
||||
const tool = 'kubectl';
|
||||
const binFile = (shell.isUnix()) ? 'kubectl' : 'kubectl.exe';
|
||||
const os = platformUrlString(shell.platform());
|
||||
|
||||
const version = await getStableKubectlVersion();
|
||||
if (failed(version)) {
|
||||
return { succeeded: false, error: version.error };
|
||||
}
|
||||
|
||||
const installFolder = getInstallFolder(shell, tool);
|
||||
mkdirp.sync(installFolder);
|
||||
|
||||
const kubectlUrl = `https://storage.googleapis.com/kubernetes-release/release/${version.result.trim()}/bin/${os}/amd64/${binFile}`;
|
||||
const downloadFile = path.join(installFolder, binFile);
|
||||
const downloadResult = await download.to(kubectlUrl, downloadFile);
|
||||
if (failed(downloadResult)) {
|
||||
return { succeeded: false, error: [`Failed to download kubectl: ${downloadResult.error[0]}`] };
|
||||
}
|
||||
|
||||
if (shell.isUnix()) {
|
||||
fs.chmodSync(downloadFile, '0777');
|
||||
}
|
||||
|
||||
await addPathToConfig(toolPathBaseKey(tool), downloadFile);
|
||||
return { succeeded: true, result: null };
|
||||
}
|
||||
|
||||
async function getStableKubectlVersion(): Promise<Errorable<string>> {
|
||||
const downloadResult = await download.toTempFile('https://storage.googleapis.com/kubernetes-release/release/stable.txt');
|
||||
if (failed(downloadResult)) {
|
||||
return { succeeded: false, error: [`Failed to establish kubectl stable version: ${downloadResult.error[0]}`] };
|
||||
}
|
||||
const version = fs.readFileSync(downloadResult.result, 'utf-8');
|
||||
fs.unlinkSync(downloadResult.result);
|
||||
return { succeeded: true, result: version };
|
||||
}
|
||||
|
||||
export function getInstallFolder(shell: Shell, tool: string): string {
|
||||
return path.join(shell.home(), `.mssql-bdc/tools/${tool}`);
|
||||
}
|
||||
|
||||
function platformUrlString(platform: Platform, supported?: Platform[]): string | null {
|
||||
if (supported && supported.indexOf(platform) < 0) {
|
||||
return null;
|
||||
}
|
||||
switch (platform) {
|
||||
case Platform.Windows: return 'windows';
|
||||
case Platform.MacOS: return 'darwin';
|
||||
case Platform.Linux: return 'linux';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,25 @@ export enum TargetClusterType {
|
||||
NewAksCluster
|
||||
}
|
||||
|
||||
export interface Succeeded<T> {
|
||||
readonly succeeded: true;
|
||||
readonly result: T;
|
||||
}
|
||||
|
||||
export interface Failed {
|
||||
readonly succeeded: false;
|
||||
readonly error: string[];
|
||||
}
|
||||
|
||||
export type Errorable<T> = Succeeded<T> | Failed;
|
||||
|
||||
export function succeeded<T>(e: Errorable<T>): e is Succeeded<T> {
|
||||
return e.succeeded;
|
||||
}
|
||||
|
||||
export function failed<T>(e: Errorable<T>): e is Failed {
|
||||
return !e.succeeded;
|
||||
}
|
||||
export interface ClusterPorts {
|
||||
sql: string;
|
||||
knox: string;
|
||||
@@ -43,4 +62,4 @@ export interface ToolInfo {
|
||||
name: string,
|
||||
description: string,
|
||||
isInstalled: boolean
|
||||
}
|
||||
}
|
||||
|
||||
117
extensions/big-data-cluster/src/kubectl/binutil.ts
Normal file
117
extensions/big-data-cluster/src/kubectl/binutil.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Shell } from '../utility/shell';
|
||||
import { Host } from './host';
|
||||
import { FS } from '../utility/fs';
|
||||
|
||||
export interface BinCheckContext {
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
}
|
||||
|
||||
interface FindBinaryResult {
|
||||
err: number | null;
|
||||
output: string;
|
||||
}
|
||||
|
||||
async function findBinary(shell: Shell, binName: string): Promise<FindBinaryResult> {
|
||||
let cmd = `which ${binName}`;
|
||||
|
||||
if (shell.isWindows()) {
|
||||
cmd = `where.exe ${binName}.exe`;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
async: true,
|
||||
env: {
|
||||
HOME: process.env.HOME,
|
||||
PATH: process.env.PATH
|
||||
}
|
||||
};
|
||||
|
||||
const execResult = await shell.execCore(cmd, opts);
|
||||
if (execResult.code) {
|
||||
return { err: execResult.code, output: execResult.stderr };
|
||||
}
|
||||
|
||||
return { err: null, output: execResult.stdout };
|
||||
}
|
||||
|
||||
export function execPath(shell: Shell, basePath: string): string {
|
||||
let bin = basePath;
|
||||
if (shell.isWindows() && bin && !(bin.endsWith('.exe'))) {
|
||||
bin = bin + '.exe';
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
type CheckPresentFailureReason = 'inferFailed' | 'configuredFileMissing';
|
||||
|
||||
function alertNoBin(host: Host, binName: string, failureReason: CheckPresentFailureReason, message: string, installDependencies: () => void): void {
|
||||
switch (failureReason) {
|
||||
case 'inferFailed':
|
||||
host.showErrorMessage(message, 'Install dependencies', 'Learn more').then(
|
||||
(str) => {
|
||||
switch (str) {
|
||||
case 'Learn more':
|
||||
host.showInformationMessage(`Add ${binName} directory to path, or set "mssql-bdc.${binName}-path" config to ${binName} binary.`);
|
||||
break;
|
||||
case 'Install dependencies':
|
||||
installDependencies();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'configuredFileMissing':
|
||||
host.showErrorMessage(message, 'Install dependencies').then(
|
||||
(str) => {
|
||||
if (str === 'Install dependencies') {
|
||||
installDependencies();
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkForBinary(context: BinCheckContext, bin: string | undefined, binName: string, inferFailedMessage: string, configuredFileMissingMessage: string, alertOnFail: boolean): Promise<boolean> {
|
||||
if (!bin) {
|
||||
const fb = await findBinary(context.shell, binName);
|
||||
|
||||
if (fb.err || fb.output.length === 0) {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'inferFailed', inferFailedMessage, context.installDependenciesCallback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
context.binFound = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.shell.isWindows) {
|
||||
context.binFound = context.fs.existsSync(bin);
|
||||
} else {
|
||||
const sr = await context.shell.exec(`ls ${bin}`);
|
||||
context.binFound = (!!sr && sr.code === 0);
|
||||
}
|
||||
if (context.binFound) {
|
||||
context.binPath = bin;
|
||||
} else {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'configuredFileMissing', configuredFileMissingMessage, context.installDependenciesCallback);
|
||||
}
|
||||
}
|
||||
|
||||
return context.binFound;
|
||||
}
|
||||
66
extensions/big-data-cluster/src/kubectl/compatibility.ts
Normal file
66
extensions/big-data-cluster/src/kubectl/compatibility.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Errorable, failed } from '../interfaces';
|
||||
|
||||
interface CompatibilityGuaranteed {
|
||||
readonly guaranteed: true;
|
||||
}
|
||||
|
||||
interface CompatibilityNotGuaranteed {
|
||||
readonly guaranteed: false;
|
||||
readonly didCheck: boolean;
|
||||
readonly clientVersion: string;
|
||||
readonly serverVersion: string;
|
||||
}
|
||||
|
||||
export type Compatibility = CompatibilityGuaranteed | CompatibilityNotGuaranteed;
|
||||
|
||||
export function isGuaranteedCompatible(c: Compatibility): c is CompatibilityGuaranteed {
|
||||
return c.guaranteed;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
readonly major: string;
|
||||
readonly minor: string;
|
||||
readonly gitVersion: string;
|
||||
}
|
||||
|
||||
export async function check(kubectlLoadJSON: (cmd: string) => Promise<Errorable<any>>): Promise<Compatibility> {
|
||||
const version = await kubectlLoadJSON('version -o json');
|
||||
if (failed(version)) {
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: false,
|
||||
clientVersion: '',
|
||||
serverVersion: ''
|
||||
};
|
||||
}
|
||||
|
||||
const clientVersion: Version = version.result.clientVersion;
|
||||
const serverVersion: Version = version.result.serverVersion;
|
||||
|
||||
if (isCompatible(clientVersion, serverVersion)) {
|
||||
return { guaranteed: true };
|
||||
}
|
||||
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: true,
|
||||
clientVersion: clientVersion.gitVersion,
|
||||
serverVersion: serverVersion.gitVersion
|
||||
};
|
||||
}
|
||||
|
||||
function isCompatible(clientVersion: Version, serverVersion: Version): boolean {
|
||||
if (clientVersion.major === serverVersion.major) {
|
||||
const clientMinor = Number.parseInt(clientVersion.minor);
|
||||
const serverMinor = Number.parseInt(serverVersion.minor);
|
||||
if (Number.isInteger(clientMinor) && Number.isInteger(serverMinor) && Math.abs(clientMinor - serverMinor) <= 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
42
extensions/big-data-cluster/src/kubectl/host.ts
Normal file
42
extensions/big-data-cluster/src/kubectl/host.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface Host {
|
||||
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
getConfiguration(key: string): any;
|
||||
onDidChangeConfiguration(listener: (ch: vscode.ConfigurationChangeEvent) => any): vscode.Disposable;
|
||||
}
|
||||
|
||||
export const host: Host = {
|
||||
showErrorMessage : showErrorMessage,
|
||||
showWarningMessage : showWarningMessage,
|
||||
showInformationMessage : showInformationMessage,
|
||||
getConfiguration : getConfiguration,
|
||||
onDidChangeConfiguration : onDidChangeConfiguration,
|
||||
};
|
||||
|
||||
function showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
}
|
||||
|
||||
function showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showWarningMessage(message, ...items);
|
||||
}
|
||||
|
||||
function showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showInformationMessage(message, ...items);
|
||||
}
|
||||
|
||||
function getConfiguration(key: string): any {
|
||||
return vscode.workspace.getConfiguration(key);
|
||||
}
|
||||
|
||||
function onDidChangeConfiguration(listener: (e: vscode.ConfigurationChangeEvent) => any): vscode.Disposable {
|
||||
return vscode.workspace.onDidChangeConfiguration(listener);
|
||||
}
|
||||
26
extensions/big-data-cluster/src/kubectl/kubeChannel.ts
Normal file
26
extensions/big-data-cluster/src/kubectl/kubeChannel.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from "vscode";
|
||||
|
||||
export interface ISqlServerBigDataClusterChannel {
|
||||
showOutput(message: any, title?: string): void;
|
||||
}
|
||||
|
||||
class SqlServerBigDataCluster implements ISqlServerBigDataClusterChannel {
|
||||
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("SQL Server big data cluster");
|
||||
|
||||
showOutput(message: any, title?: string): void {
|
||||
if (title) {
|
||||
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, ' ').trim(); // YYYY-MM-DD HH:mm:ss.sss
|
||||
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
|
||||
this.channel.appendLine(hightlightingTitle);
|
||||
}
|
||||
this.channel.appendLine(message);
|
||||
this.channel.show();
|
||||
}
|
||||
}
|
||||
|
||||
export const sqlserverbigdataclusterchannel: ISqlServerBigDataClusterChannel = new SqlServerBigDataCluster();
|
||||
130
extensions/big-data-cluster/src/kubectl/kubectl.ts
Normal file
130
extensions/big-data-cluster/src/kubectl/kubectl.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Host } from './host';
|
||||
import { FS } from '../utility/fs';
|
||||
import { Shell, ShellResult } from '../utility/shell';
|
||||
import * as binutil from './binutil';
|
||||
import { Errorable } from '../interfaces';
|
||||
import * as compatibility from './compatibility';
|
||||
import { getToolPath } from '../config/config';
|
||||
|
||||
export interface Kubectl {
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean>;
|
||||
asJson<T>(command: string): Promise<Errorable<T>>;
|
||||
}
|
||||
|
||||
interface Context {
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
}
|
||||
|
||||
class KubectlImpl implements Kubectl {
|
||||
constructor(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void, kubectlFound: boolean) {
|
||||
this.context = { host : host, fs : fs, shell : shell, installDependenciesCallback : installDependenciesCallback, binFound : kubectlFound, binPath : 'kubectl' };
|
||||
}
|
||||
|
||||
private readonly context: Context;
|
||||
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
return checkPresent(this.context, errorMessageMode);
|
||||
}
|
||||
asJson<T>(command: string): Promise<Errorable<T>> {
|
||||
return asJson(this.context, command);
|
||||
}
|
||||
}
|
||||
|
||||
export function create(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void): Kubectl {
|
||||
return new KubectlImpl(host, fs, shell, installDependenciesCallback, false);
|
||||
}
|
||||
|
||||
export enum CheckPresentMessageMode {
|
||||
Command,
|
||||
Activation,
|
||||
Silent,
|
||||
}
|
||||
|
||||
async function checkPresent(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
if (context.binFound) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return await checkForKubectlInternal(context, errorMessageMode);
|
||||
}
|
||||
|
||||
async function checkForKubectlInternal(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
const binName = 'kubectl';
|
||||
const bin = getToolPath(context.host, context.shell, binName);
|
||||
|
||||
const contextMessage = getCheckKubectlContextMessage(errorMessageMode);
|
||||
const inferFailedMessage = `Could not find "${binName}" binary.${contextMessage}`;
|
||||
const configuredFileMissingMessage = `${bin} is not installed. ${contextMessage}`;
|
||||
|
||||
return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== CheckPresentMessageMode.Silent);
|
||||
}
|
||||
|
||||
function getCheckKubectlContextMessage(errorMessageMode: CheckPresentMessageMode): string {
|
||||
if (errorMessageMode === CheckPresentMessageMode.Activation) {
|
||||
return ' SQL Server Big data cluster requires kubernetes.';
|
||||
} else if (errorMessageMode === CheckPresentMessageMode.Command) {
|
||||
return ' Cannot execute command.';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function invokeAsync(context: Context, command: string, stdin?: string): Promise<ShellResult | undefined> {
|
||||
if (await checkPresent(context, CheckPresentMessageMode.Command)) {
|
||||
const bin = baseKubectlPath(context);
|
||||
const cmd = `${bin} ${command}`;
|
||||
const sr = await context.shell.exec(cmd, stdin);
|
||||
if (sr && sr.code !== 0) {
|
||||
checkPossibleIncompatibility(context);
|
||||
}
|
||||
return sr;
|
||||
} else {
|
||||
return { code: -1, stdout: '', stderr: '' };
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: invalidate this when the context changes or if we know kubectl has changed (e.g. config)
|
||||
let checkedCompatibility = false; // We don't want to spam the user (or CPU!) repeatedly running the version check
|
||||
|
||||
async function checkPossibleIncompatibility(context: Context): Promise<void> {
|
||||
if (checkedCompatibility) {
|
||||
return;
|
||||
}
|
||||
checkedCompatibility = true;
|
||||
const compat = await compatibility.check((cmd) => asJson<compatibility.Version>(context, cmd));
|
||||
if (!compatibility.isGuaranteedCompatible(compat) && compat.didCheck) {
|
||||
const versionAlert = `kubectl version ${compat.clientVersion} may be incompatible with cluster Kubernetes version ${compat.serverVersion}`;
|
||||
context.host.showWarningMessage(versionAlert);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function baseKubectlPath(context: Context): string {
|
||||
let bin = getToolPath(context.host, context.shell, 'kubectl');
|
||||
if (!bin) {
|
||||
bin = 'kubectl';
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
async function asJson<T>(context: Context, command: string): Promise<Errorable<T>> {
|
||||
const shellResult = await invokeAsync(context, command);
|
||||
if (!shellResult) {
|
||||
return { succeeded: false, error: [`Unable to run command (${command})`] };
|
||||
}
|
||||
|
||||
if (shellResult.code === 0) {
|
||||
return { succeeded: true, result: JSON.parse(shellResult.stdout.trim()) as T };
|
||||
|
||||
}
|
||||
return { succeeded: false, error: [ shellResult.stderr ] };
|
||||
}
|
||||
86
extensions/big-data-cluster/src/kubectl/kubectlUtils.ts
Normal file
86
extensions/big-data-cluster/src/kubectl/kubectlUtils.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from "vscode";
|
||||
import { Kubectl } from "./kubectl";
|
||||
import { failed } from "../interfaces";
|
||||
|
||||
export interface KubectlContext {
|
||||
readonly clusterName: string;
|
||||
readonly contextName: string;
|
||||
readonly userName: string;
|
||||
readonly active: boolean;
|
||||
}
|
||||
|
||||
interface Kubeconfig {
|
||||
readonly apiVersion: string;
|
||||
readonly 'current-context': string;
|
||||
readonly clusters: {
|
||||
readonly name: string;
|
||||
readonly cluster: {
|
||||
readonly server: string;
|
||||
readonly 'certificate-authority'?: string;
|
||||
readonly 'certificate-authority-data'?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly contexts: {
|
||||
readonly name: string;
|
||||
readonly context: {
|
||||
readonly cluster: string;
|
||||
readonly user: string;
|
||||
readonly namespace?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly users: {
|
||||
readonly name: string;
|
||||
readonly user: {};
|
||||
}[] | undefined;
|
||||
}
|
||||
|
||||
export interface ClusterConfig {
|
||||
readonly server: string;
|
||||
readonly certificateAuthority: string | undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function getKubeconfig(kubectl: Kubectl): Promise<Kubeconfig | null> {
|
||||
const shellResult = await kubectl.asJson<any>("config view -o json");
|
||||
if (failed(shellResult)) {
|
||||
vscode.window.showErrorMessage(shellResult.error[0]);
|
||||
return null;
|
||||
}
|
||||
return shellResult.result;
|
||||
}
|
||||
|
||||
export async function getCurrentClusterConfig(kubectl: Kubectl): Promise<ClusterConfig | undefined> {
|
||||
const kubeConfig = await getKubeconfig(kubectl);
|
||||
if (!kubeConfig || !kubeConfig.clusters || !kubeConfig.contexts) {
|
||||
return undefined;
|
||||
}
|
||||
const contextConfig = kubeConfig.contexts.find((context) => context.name === kubeConfig["current-context"])!;
|
||||
const clusterConfig = kubeConfig.clusters.find((cluster) => cluster.name === contextConfig.context.cluster)!;
|
||||
return {
|
||||
server: clusterConfig.cluster.server,
|
||||
certificateAuthority: clusterConfig.cluster["certificate-authority"]
|
||||
};
|
||||
}
|
||||
|
||||
export async function getContexts(kubectl: Kubectl): Promise<KubectlContext[]> {
|
||||
const kubectlConfig = await getKubeconfig(kubectl);
|
||||
if (!kubectlConfig) {
|
||||
return [];
|
||||
}
|
||||
const currentContext = kubectlConfig["current-context"];
|
||||
const contexts = kubectlConfig.contexts || [];
|
||||
return contexts.map((c) => {
|
||||
return {
|
||||
clusterName: c.context.cluster,
|
||||
contextName: c.name,
|
||||
userName: c.context.user,
|
||||
active: c.name === currentContext
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -6,10 +6,22 @@
|
||||
|
||||
import vscode = require('vscode');
|
||||
import { MainController } from './mainController';
|
||||
|
||||
import { fs } from './utility/fs';
|
||||
|
||||
import { host } from './kubectl/host';
|
||||
import { sqlserverbigdataclusterchannel } from './kubectl/kubeChannel';
|
||||
import { shell, Shell } from './utility/shell';
|
||||
import { CheckPresentMessageMode, create as kubectlCreate } from './kubectl/kubectl';
|
||||
import { installKubectl } from './installer/installer';
|
||||
import { Errorable, failed } from './interfaces';
|
||||
|
||||
const kubectl = kubectlCreate(host, fs, shell, installDependencies);
|
||||
export let controller: MainController;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
controller = new MainController(context);
|
||||
kubectl.checkPresent(CheckPresentMessageMode.Activation);
|
||||
controller = new MainController(context, kubectl);
|
||||
controller.activate();
|
||||
}
|
||||
|
||||
@@ -19,3 +31,28 @@ export function deactivate(): void {
|
||||
controller.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
export async function installDependencies() {
|
||||
const gotKubectl = await kubectl.checkPresent(CheckPresentMessageMode.Silent);
|
||||
|
||||
|
||||
const installPromises = [
|
||||
installDependency("kubectl", gotKubectl, installKubectl),
|
||||
];
|
||||
|
||||
await Promise.all(installPromises);
|
||||
|
||||
sqlserverbigdataclusterchannel.showOutput("Done");
|
||||
}
|
||||
|
||||
async function installDependency(name: string, alreadyGot: boolean, installFunc: (shell: Shell) => Promise<Errorable<null>>): Promise<void> {
|
||||
if (alreadyGot) {
|
||||
sqlserverbigdataclusterchannel.showOutput(`Already got ${name}...`);
|
||||
} else {
|
||||
sqlserverbigdataclusterchannel.showOutput(`Installing ${name}...`);
|
||||
const result = await installFunc(shell);
|
||||
if (failed(result)) {
|
||||
sqlserverbigdataclusterchannel.showOutput(`Unable to install ${name}: ${result.error[0]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,17 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { CreateClusterWizard } from './wizards/create-cluster/createClusterWizard';
|
||||
|
||||
import { Kubectl } from './kubectl/kubectl';
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export class MainController {
|
||||
protected _context: vscode.ExtensionContext;
|
||||
protected _kubectl : Kubectl;
|
||||
|
||||
public constructor(context: vscode.ExtensionContext) {
|
||||
public constructor(context: vscode.ExtensionContext, kubectl: Kubectl) {
|
||||
this._context = context;
|
||||
this._kubectl = kubectl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,7 +24,7 @@ export class MainController {
|
||||
*/
|
||||
public activate(): void {
|
||||
vscode.commands.registerCommand('mssql.cluster.create', () => {
|
||||
let wizard = new CreateClusterWizard(this._context);
|
||||
let wizard = new CreateClusterWizard(this._context, this._kubectl);
|
||||
wizard.open();
|
||||
});
|
||||
}
|
||||
|
||||
65
extensions/big-data-cluster/src/utility/fs.ts
Normal file
65
extensions/big-data-cluster/src/utility/fs.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as sysfs from 'fs';
|
||||
|
||||
export interface FS {
|
||||
existsSync(path: string): boolean;
|
||||
readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
|
||||
readFileSync(filename: string, encoding: string): string;
|
||||
readFileToBufferSync(filename: string): Buffer;
|
||||
writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
|
||||
writeFileSync(filename: string, data: any): void;
|
||||
dirSync(path: string): string[];
|
||||
unlinkAsync(path: string): Promise<void>;
|
||||
existsAsync(path: string): Promise<boolean>;
|
||||
openAsync(path: string, flags: string): Promise<void>;
|
||||
statSync(path: string): sysfs.Stats;
|
||||
}
|
||||
|
||||
export const fs: FS = {
|
||||
existsSync: (path) => sysfs.existsSync(path),
|
||||
readFile: (filename, encoding, callback) => sysfs.readFile(filename, encoding, callback),
|
||||
readFileSync: (filename, encoding) => sysfs.readFileSync(filename, encoding),
|
||||
readFileToBufferSync: (filename) => sysfs.readFileSync(filename),
|
||||
writeFile: (filename, data, callback) => sysfs.writeFile(filename, data, callback),
|
||||
writeFileSync: (filename, data) => sysfs.writeFileSync(filename, data),
|
||||
dirSync: (path) => sysfs.readdirSync(path),
|
||||
|
||||
unlinkAsync: (path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
sysfs.unlink(path, (error) => {
|
||||
if (error) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
existsAsync: (path) => {
|
||||
return new Promise((resolve) => {
|
||||
sysfs.exists(path, (exists) => {
|
||||
resolve(exists);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
openAsync: (path, flags) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
sysfs.open(path, flags, (error, _fd) => {
|
||||
if (error) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
statSync: (path) => sysfs.statSync(path)
|
||||
};
|
||||
204
extensions/big-data-cluster/src/utility/shell.ts
Normal file
204
extensions/big-data-cluster/src/utility/shell.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as shelljs from 'shelljs';
|
||||
import * as path from 'path';
|
||||
import { getActiveKubeconfig, getToolPath } from '../config/config';
|
||||
import { host } from '../kubectl/host';
|
||||
|
||||
export enum Platform {
|
||||
Windows,
|
||||
MacOS,
|
||||
Linux,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
export interface ExecCallback extends shelljs.ExecCallback {}
|
||||
|
||||
export interface Shell {
|
||||
isWindows(): boolean;
|
||||
isUnix(): boolean;
|
||||
platform(): Platform;
|
||||
home(): string;
|
||||
combinePath(basePath: string, relativePath: string): string;
|
||||
fileUri(filePath: string): vscode.Uri;
|
||||
execOpts(): any;
|
||||
exec(cmd: string, stdin?: string): Promise<ShellResult | undefined>;
|
||||
execCore(cmd: string, opts: any, stdin?: string): Promise<ShellResult>;
|
||||
unquotedPath(path: string): string;
|
||||
which(bin: string): string | null;
|
||||
cat(path: string): string;
|
||||
ls(path: string): string[];
|
||||
}
|
||||
|
||||
export const shell: Shell = {
|
||||
isWindows : isWindows,
|
||||
isUnix : isUnix,
|
||||
platform : platform,
|
||||
home : home,
|
||||
combinePath : combinePath,
|
||||
fileUri : fileUri,
|
||||
execOpts : execOpts,
|
||||
exec : exec,
|
||||
execCore : execCore,
|
||||
unquotedPath : unquotedPath,
|
||||
which: which,
|
||||
cat: cat,
|
||||
ls: ls,
|
||||
};
|
||||
|
||||
const WINDOWS: string = 'win32';
|
||||
|
||||
export interface ShellResult {
|
||||
readonly code: number;
|
||||
readonly stdout: string;
|
||||
readonly stderr: string;
|
||||
}
|
||||
|
||||
export type ShellHandler = (code: number, stdout: string, stderr: string) => void;
|
||||
|
||||
function isWindows(): boolean {
|
||||
return (process.platform === WINDOWS);
|
||||
}
|
||||
|
||||
function isUnix(): boolean {
|
||||
return !isWindows();
|
||||
}
|
||||
|
||||
function platform(): Platform {
|
||||
switch (process.platform) {
|
||||
case 'win32': return Platform.Windows;
|
||||
case 'darwin': return Platform.MacOS;
|
||||
case 'linux': return Platform.Linux;
|
||||
default: return Platform.Unsupported;
|
||||
}
|
||||
}
|
||||
|
||||
function concatIfBoth(s1: string | undefined, s2: string | undefined): string | undefined {
|
||||
return s1 && s2 ? s1.concat(s2) : undefined;
|
||||
}
|
||||
|
||||
function home(): string {
|
||||
return process.env['HOME'] ||
|
||||
concatIfBoth(process.env['HOMEDRIVE'], process.env['HOMEPATH']) ||
|
||||
process.env['USERPROFILE'] ||
|
||||
'';
|
||||
}
|
||||
|
||||
function combinePath(basePath: string, relativePath: string) {
|
||||
let separator = '/';
|
||||
if (isWindows()) {
|
||||
relativePath = relativePath.replace(/\//g, '\\');
|
||||
separator = '\\';
|
||||
}
|
||||
return basePath + separator + relativePath;
|
||||
}
|
||||
|
||||
function isWindowsFilePath(filePath: string) {
|
||||
return filePath[1] === ':' && filePath[2] === '\\';
|
||||
}
|
||||
|
||||
function fileUri(filePath: string): vscode.Uri {
|
||||
if (isWindowsFilePath(filePath)) {
|
||||
return vscode.Uri.parse('file:///' + filePath.replace(/\\/g, '/'));
|
||||
}
|
||||
return vscode.Uri.parse('file://' + filePath);
|
||||
}
|
||||
|
||||
function execOpts(): any {
|
||||
let env = process.env;
|
||||
if (isWindows()) {
|
||||
env = Object.assign({ }, env, { HOME: home() });
|
||||
}
|
||||
env = shellEnvironment(env);
|
||||
const opts = {
|
||||
cwd: vscode.workspace.rootPath,
|
||||
env: env,
|
||||
async: true
|
||||
};
|
||||
return opts;
|
||||
}
|
||||
|
||||
async function exec(cmd: string, stdin?: string): Promise<ShellResult | undefined> {
|
||||
try {
|
||||
return await execCore(cmd, execOpts(), stdin);
|
||||
} catch (ex) {
|
||||
vscode.window.showErrorMessage(ex);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function execCore(cmd: string, opts: any, stdin?: string): Promise<ShellResult> {
|
||||
return new Promise<ShellResult>((resolve) => {
|
||||
const proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({code : code, stdout : stdout, stderr : stderr}));
|
||||
if (stdin) {
|
||||
proc.stdin.end(stdin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function unquotedPath(path: string): string {
|
||||
if (isWindows() && path && path.length > 1 && path.startsWith('"') && path.endsWith('"')) {
|
||||
return path.substring(1, path.length - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
export function shellEnvironment(baseEnvironment: any): any {
|
||||
const env = Object.assign({}, baseEnvironment);
|
||||
const pathVariable = pathVariableName(env);
|
||||
for (const tool of ['kubectl']) {
|
||||
const toolPath = getToolPath(host, shell, tool);
|
||||
if (toolPath) {
|
||||
const toolDirectory = path.dirname(toolPath);
|
||||
const currentPath = env[pathVariable];
|
||||
env[pathVariable] = toolDirectory + (currentPath ? `${pathEntrySeparator()}${currentPath}` : '');
|
||||
}
|
||||
}
|
||||
|
||||
const kubeconfig = getActiveKubeconfig();
|
||||
if (kubeconfig) {
|
||||
env['KUBECONFIG'] = kubeconfig;
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
function pathVariableName(env: any): string {
|
||||
if (isWindows()) {
|
||||
for (const v of Object.keys(env)) {
|
||||
if (v.toLowerCase() === "path") {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "PATH";
|
||||
}
|
||||
|
||||
function pathEntrySeparator() {
|
||||
return isWindows() ? ';' : ':';
|
||||
}
|
||||
|
||||
function which(bin: string): string | null {
|
||||
return shelljs.which(bin);
|
||||
}
|
||||
|
||||
function cat(path: string): string {
|
||||
return shelljs.cat(path);
|
||||
}
|
||||
|
||||
function ls(path: string): string[] {
|
||||
return shelljs.ls(path);
|
||||
}
|
||||
|
||||
export function shellMessage(sr: ShellResult | undefined, invocationFailureMessage: string): string {
|
||||
if (!sr) {
|
||||
return invocationFailureMessage;
|
||||
}
|
||||
return sr.code === 0 ? sr.stdout : sr.stderr;
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
import { IKubeConfigParser } from '../../data/kubeConfigParser';
|
||||
import { ClusterInfo, TargetClusterType, ClusterPorts, ContainerRegistryInfo, TargetClusterTypeInfo, ToolInfo } from '../../interfaces';
|
||||
import { getContexts, KubectlContext } from '../../kubectl/kubectlUtils';
|
||||
import { Kubectl } from '../../kubectl/kubectl';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -14,11 +16,11 @@ export class CreateClusterModel {
|
||||
|
||||
private _tmp_tools_installed: boolean = false;
|
||||
|
||||
constructor(private _kubeConfigParser: IKubeConfigParser) {
|
||||
constructor(private _kubectl : Kubectl) {
|
||||
}
|
||||
|
||||
public loadClusters(configPath: string): ClusterInfo[] {
|
||||
return this._kubeConfigParser.parse(configPath);
|
||||
public async loadClusters(): Promise<KubectlContext[]> {
|
||||
return await getContexts(this._kubectl);
|
||||
}
|
||||
|
||||
public getDefaultPorts(): Thenable<ClusterPorts> {
|
||||
@@ -107,7 +109,7 @@ export class CreateClusterModel {
|
||||
|
||||
public targetClusterType: TargetClusterType;
|
||||
|
||||
public selectedCluster: ClusterInfo;
|
||||
public selectedCluster: KubectlContext;
|
||||
|
||||
public adminUserName: string;
|
||||
|
||||
|
||||
@@ -9,18 +9,17 @@ import { SelectExistingClusterPage } from './pages/selectExistingClusterPage';
|
||||
import { SummaryPage } from './pages/summaryPage';
|
||||
import { SettingsPage } from './pages/settingsPage';
|
||||
import { ClusterProfilePage } from './pages/clusterProfilePage';
|
||||
import { TestKubeConfigParser } from '../../data/kubeConfigParser';
|
||||
import { ExtensionContext } from 'vscode';
|
||||
import { WizardBase } from '../wizardBase';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Kubectl } from '../../kubectl/kubectl';
|
||||
import { SelectTargetClusterTypePage } from './pages/selectTargetClusterTypePage';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class CreateClusterWizard extends WizardBase<CreateClusterModel, CreateClusterWizard> {
|
||||
constructor(context: ExtensionContext) {
|
||||
let configParser = new TestKubeConfigParser();
|
||||
let model = new CreateClusterModel(configParser);
|
||||
constructor(context: ExtensionContext, kubectl: Kubectl) {
|
||||
let model = new CreateClusterModel(kubectl);
|
||||
super(model, context, localize('bdc-create.wizardTitle', 'Create a big data cluster'));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import * as os from 'os';
|
||||
import { WizardPageBase } from '../../wizardPageBase';
|
||||
import { CreateClusterWizard } from '../createClusterWizard';
|
||||
import { TargetClusterType } from '../../../interfaces';
|
||||
import { setActiveKubeconfig } from '../../../config/config';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -101,7 +103,7 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
defaultUri: vscode.Uri.file(os.homedir()),
|
||||
openLabel: localize('bdc-selectKubeConfigFileText', 'Select'),
|
||||
filters: {
|
||||
'KubeConfig Files': ['kubeconfig'],
|
||||
'KubeConfig Files': ['*'],
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -114,8 +116,9 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
let fileUri = fileUris[0];
|
||||
|
||||
configFileInput.value = fileUri.fsPath;
|
||||
await setActiveKubeconfig(fileUri.fsPath);
|
||||
|
||||
let clusters = self.wizard.model.loadClusters(fileUri.fsPath);
|
||||
let clusters = await self.wizard.model.loadClusters();
|
||||
|
||||
self.cards = [];
|
||||
if (clusters.length !== 0) {
|
||||
@@ -124,8 +127,8 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
let cluster = clusters[i];
|
||||
let card = view.modelBuilder.card().withProperties({
|
||||
selected: i === 0,
|
||||
label: cluster.name,
|
||||
descriptions: [cluster.displayName, cluster.user],
|
||||
label: cluster.clusterName,
|
||||
descriptions: [cluster.clusterName, cluster.userName],
|
||||
cardType: sqlops.CardType.ListItem,
|
||||
iconPath: {
|
||||
dark: self.wizard.context.asAbsolutePath('images/cluster_inverse.svg'),
|
||||
|
||||
@@ -7,11 +7,92 @@ ansi-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
base64-js@^1.0.2:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
||||
integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||
|
||||
buffer-alloc@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||
dependencies:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
|
||||
buffer-fill@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
|
||||
|
||||
buffer@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6"
|
||||
integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==
|
||||
dependencies:
|
||||
base64-js "^1.0.2"
|
||||
ieee754 "^1.1.4"
|
||||
|
||||
caw@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95"
|
||||
integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==
|
||||
dependencies:
|
||||
get-proxy "^2.0.0"
|
||||
isurl "^1.0.0-alpha5"
|
||||
tunnel-agent "^0.6.0"
|
||||
url-to-options "^1.0.1"
|
||||
|
||||
charenc@~0.0.1:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
commander@~2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
|
||||
integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=
|
||||
dependencies:
|
||||
graceful-readlink ">= 1.0.0"
|
||||
|
||||
config-chain@^1.1.11:
|
||||
version "1.1.12"
|
||||
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
|
||||
integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==
|
||||
dependencies:
|
||||
ini "^1.3.4"
|
||||
proto-list "~1.2.1"
|
||||
|
||||
content-disposition@^0.5.2:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
|
||||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
crypt@~0.0.1:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||
@@ -31,16 +112,293 @@ debug@^3.1.0:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decompress-response@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
|
||||
integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==
|
||||
dependencies:
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
tar-stream "^1.5.2"
|
||||
|
||||
decompress-tarbz2@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b"
|
||||
integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==
|
||||
dependencies:
|
||||
decompress-tar "^4.1.0"
|
||||
file-type "^6.1.0"
|
||||
is-stream "^1.1.0"
|
||||
seek-bzip "^1.0.5"
|
||||
unbzip2-stream "^1.0.9"
|
||||
|
||||
decompress-targz@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee"
|
||||
integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==
|
||||
dependencies:
|
||||
decompress-tar "^4.1.1"
|
||||
file-type "^5.2.0"
|
||||
is-stream "^1.1.0"
|
||||
|
||||
decompress-unzip@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69"
|
||||
integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k=
|
||||
dependencies:
|
||||
file-type "^3.8.0"
|
||||
get-stream "^2.2.0"
|
||||
pify "^2.3.0"
|
||||
yauzl "^2.4.2"
|
||||
|
||||
decompress@^4.0.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d"
|
||||
integrity sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=
|
||||
dependencies:
|
||||
decompress-tar "^4.0.0"
|
||||
decompress-tarbz2 "^4.0.0"
|
||||
decompress-targz "^4.0.0"
|
||||
decompress-unzip "^4.0.1"
|
||||
graceful-fs "^4.1.10"
|
||||
make-dir "^1.0.0"
|
||||
pify "^2.3.0"
|
||||
strip-dirs "^2.0.0"
|
||||
|
||||
download@^6.2.5:
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714"
|
||||
integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==
|
||||
dependencies:
|
||||
caw "^2.0.0"
|
||||
content-disposition "^0.5.2"
|
||||
decompress "^4.0.0"
|
||||
ext-name "^5.0.0"
|
||||
file-type "5.2.0"
|
||||
filenamify "^2.0.0"
|
||||
get-stream "^3.0.0"
|
||||
got "^7.0.0"
|
||||
make-dir "^1.0.0"
|
||||
p-event "^1.0.0"
|
||||
pify "^3.0.0"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
|
||||
|
||||
end-of-stream@^1.0.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
|
||||
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
escape-string-regexp@^1.0.2:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
ext-list@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
|
||||
integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
|
||||
dependencies:
|
||||
mime-db "^1.28.0"
|
||||
|
||||
ext-name@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6"
|
||||
integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==
|
||||
dependencies:
|
||||
ext-list "^2.0.0"
|
||||
sort-keys-length "^1.0.0"
|
||||
|
||||
fd-slicer@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
||||
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
|
||||
dependencies:
|
||||
pend "~1.2.0"
|
||||
|
||||
file-type@5.2.0, file-type@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6"
|
||||
integrity sha1-LdvqfHP/42No365J3DOMBYwritY=
|
||||
|
||||
file-type@^3.8.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
|
||||
integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek=
|
||||
|
||||
file-type@^6.1.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
|
||||
integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==
|
||||
|
||||
filename-reserved-regex@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229"
|
||||
integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik=
|
||||
|
||||
filenamify@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9"
|
||||
integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==
|
||||
dependencies:
|
||||
filename-reserved-regex "^2.0.0"
|
||||
strip-outer "^1.0.0"
|
||||
trim-repeated "^1.0.0"
|
||||
|
||||
fs-constants@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||
|
||||
get-proxy@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93"
|
||||
integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==
|
||||
dependencies:
|
||||
npm-conf "^1.1.0"
|
||||
|
||||
get-stream@^2.2.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de"
|
||||
integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||
|
||||
got@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
|
||||
integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==
|
||||
dependencies:
|
||||
decompress-response "^3.2.0"
|
||||
duplexer3 "^0.1.4"
|
||||
get-stream "^3.0.0"
|
||||
is-plain-obj "^1.1.0"
|
||||
is-retry-allowed "^1.0.0"
|
||||
is-stream "^1.0.0"
|
||||
isurl "^1.0.0-alpha5"
|
||||
lowercase-keys "^1.0.0"
|
||||
p-cancelable "^0.3.0"
|
||||
p-timeout "^1.1.1"
|
||||
safe-buffer "^5.0.1"
|
||||
timed-out "^4.0.0"
|
||||
url-parse-lax "^1.0.0"
|
||||
url-to-options "^1.0.1"
|
||||
|
||||
graceful-fs@^4.1.10:
|
||||
version "4.1.15"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||
|
||||
"graceful-readlink@>= 1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
||||
|
||||
has-symbol-support-x@^1.4.1:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
|
||||
integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
|
||||
|
||||
has-to-string-tag-x@^1.2.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
|
||||
integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==
|
||||
dependencies:
|
||||
has-symbol-support-x "^1.4.1"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.12"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
|
||||
integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==
|
||||
|
||||
inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||
|
||||
is-buffer@~1.1.1:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
is-natural-number@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
|
||||
integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=
|
||||
|
||||
is-object@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
|
||||
integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
|
||||
|
||||
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||
|
||||
is-retry-allowed@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
|
||||
integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
|
||||
|
||||
is-stream@^1.0.0, is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isurl@^1.0.0-alpha5:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
|
||||
integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==
|
||||
dependencies:
|
||||
has-to-string-tag-x "^1.2.0"
|
||||
is-object "^1.0.1"
|
||||
|
||||
lodash@^4.16.4:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
|
||||
lowercase-keys@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||
integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
md5@^2.1.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
|
||||
@@ -50,6 +408,16 @@ md5@^2.1.0:
|
||||
crypt "~0.0.1"
|
||||
is-buffer "~1.1.1"
|
||||
|
||||
mime-db@^1.28.0:
|
||||
version "1.38.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
|
||||
integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
@@ -91,6 +459,138 @@ ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
npm-conf@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9"
|
||||
integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==
|
||||
dependencies:
|
||||
config-chain "^1.1.11"
|
||||
pify "^3.0.0"
|
||||
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
p-cancelable@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
|
||||
integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==
|
||||
|
||||
p-event@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085"
|
||||
integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=
|
||||
dependencies:
|
||||
p-timeout "^1.1.1"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||
|
||||
p-timeout@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
|
||||
integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
|
||||
|
||||
pinkie-promise@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
|
||||
integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
|
||||
dependencies:
|
||||
pinkie "^2.0.0"
|
||||
|
||||
pinkie@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
|
||||
|
||||
prepend-http@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
|
||||
|
||||
readable-stream@^2.3.0, readable-stream@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
seek-bzip@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
|
||||
integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=
|
||||
dependencies:
|
||||
commander "~2.8.1"
|
||||
|
||||
sort-keys-length@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
|
||||
integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
|
||||
dependencies:
|
||||
sort-keys "^1.0.0"
|
||||
|
||||
sort-keys@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
|
||||
integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
|
||||
dependencies:
|
||||
is-plain-obj "^1.0.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
@@ -98,12 +598,111 @@ strip-ansi@^4.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-dirs@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5"
|
||||
integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==
|
||||
dependencies:
|
||||
is-natural-number "^4.0.1"
|
||||
|
||||
strip-outer@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631"
|
||||
integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.2"
|
||||
|
||||
tar-stream@^1.5.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
|
||||
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
buffer-alloc "^1.2.0"
|
||||
end-of-stream "^1.0.0"
|
||||
fs-constants "^1.0.0"
|
||||
readable-stream "^2.3.0"
|
||||
to-buffer "^1.1.1"
|
||||
xtend "^4.0.0"
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
|
||||
timed-out@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
|
||||
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
|
||||
|
||||
to-buffer@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
|
||||
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||
|
||||
trim-repeated@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21"
|
||||
integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.2"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
unbzip2-stream@^1.0.9:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a"
|
||||
integrity sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==
|
||||
dependencies:
|
||||
buffer "^5.2.1"
|
||||
through "^2.3.8"
|
||||
|
||||
url-parse-lax@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
|
||||
integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
|
||||
dependencies:
|
||||
prepend-http "^1.0.1"
|
||||
|
||||
url-to-options@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
|
||||
integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
vscode-nls@^3.2.1:
|
||||
version "3.2.5"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.5.tgz#25520c1955108036dec607c85e00a522f247f1a4"
|
||||
integrity sha512-ITtoh3V4AkWXMmp3TB97vsMaHRgHhsSFPsUdzlueSL+dRZbSNTZeOmdQv60kjCV306ghPxhDeoNUEm3+EZMuyw==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xml@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
|
||||
integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
|
||||
|
||||
yauzl@^2.4.2:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
|
||||
dependencies:
|
||||
buffer-crc32 "~0.2.3"
|
||||
fd-slicer "~1.1.0"
|
||||
|
||||
Reference in New Issue
Block a user