vs-deploy
Version:
Commands for deploying files of your workspace to a destination.
1,086 lines (1,085 loc) • 196 kB
JavaScript
"use strict";
/// <reference types="node" />
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
// The MIT License (MIT)
//
// vs-deploy (https://github.com/mkloubert/vs-deploy)
// Copyright (c) Marcel Joachim Kloubert <marcel.kloubert@gmx.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
const deploy_buttons = require("./buttons");
const deploy_commands = require("./commands");
const deploy_config = require("./config");
const deploy_contracts = require("./contracts");
const deploy_diff = require("./diff");
const deploy_helpers = require("./helpers");
const deploy_globals = require("./globals");
const deploy_objects = require("./objects");
const deploy_operations = require("./operations");
const deploy_packages = require("./packages");
const deploy_plugins = require("./plugins");
const deploy_switch = require("./switch");
const deploy_sync = require("./sync");
const deploy_targets = require("./targets");
const deploy_templates = require("./templates");
const deploy_urls = require("./urls");
const deploy_values = require("./values");
const deploy_workspace = require("./workspace");
const host_1 = require("./host");
const Events = require("events");
const FS = require("fs");
const Glob = require('glob');
const i18 = require("./i18");
const Moment = require("moment");
const OS = require("os");
const Path = require("path");
const TMP = require("tmp");
const vscode = require("vscode");
const Workflows = require("node-workflows");
const AFTER_DEPLOYMENT_BUTTON_COLORS = {
's': [
'ffffff',
'eeeeee',
'dddddd',
],
'w': [
'ffff00',
'eeee00',
'dddd00',
],
'e': [
'000000',
'111111',
'222222',
],
};
let nextCancelDeployFileCommandId = Number.MAX_SAFE_INTEGER;
let nextCancelDeployWorkspaceCommandId = Number.MAX_SAFE_INTEGER;
let nextCancelPullFileCommandId = Number.MAX_SAFE_INTEGER;
let nextCancelPullWorkspaceCommandId = Number.MAX_SAFE_INTEGER;
/**
* Deployer class.
*/
class Deployer extends Events.EventEmitter {
/**
* Initializes a new instance of that class.
*
* @param {vscode.ExtensionContext} context The underlying extension context.
* @param {vscode.OutputChannel} outputChannel The global output channel to use.
* @param {deploy_contracts.PackageFile} pkgFile The package file of that extension.
*/
constructor(context, outputChannel, pkgFile) {
super();
/**
* Stores the current list of global events.
*/
this._EVENTS = [];
/**
* The global state value for deploy operation scripts.
*/
this._globalScriptOperationState = {};
/**
* Stores if 'deploy on change' feature is enabled or not.
*/
this._isDeployOnChangeEnabled = true;
/**
* Stores if 'deploy on change' feature is freezed or not.
*/
this._isDeployOnChangeFreezed = false;
/**
* Stores if 'deploy on save' feature is enabled or not.
*/
this._isDeployOnSaveEnabled = true;
/**
* Stores if extension is reloading its configuration or not.
*/
this._isReloadingConfig = false;
/**
* Stores if 'sync when open' feature is enabled or not.
*/
this._isSyncWhenOpenEnabled = true;
this._NEXT_AFTER_DEPLOYMENT_BUTTON_COLORS = {
's': 0,
'w': 0,
'e': 0,
};
/**
* The states values for deploy operation scripts.
*/
this._scriptOperationStates = {};
/**
* Stores the packages that are currently deploy.
*/
this._WORKSPACE_IN_PROGRESS = {};
this._CONTEXT = context;
this._OUTPUT_CHANNEL = outputChannel;
this._PACKAGE_FILE = pkgFile;
this._QUICK_DEPLOY_STATUS_ITEM = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
this._QUICK_DEPLOY_STATUS_ITEM.command = 'extension.deploy.quickDeploy';
this._AFTER_DEPLOYMENT_STATUS_ITEM = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
this._AFTER_DEPLOYMENT_STATUS_ITEM.command = 'extension.deploy.openOutputAfterDeploment';
this._AFTER_DEPLOYMENT_STATUS_ITEM.tooltip = 'Click here to open output...';
}
/**
* Invokes 'after deployed' operations for a target.
*
* @param {string[]} files The files that have been deployed.
* @param {deploy_contracts.DeployTarget} target The target.
*
* @return {Promise<boolean>} The promise.
*/
afterDeployment(files, target) {
let me = this;
return new Promise((resolve, reject) => {
let afterDeployedOperations = deploy_helpers.asArray(target.deployed)
.filter(x => x);
let hasCancelled = false;
let completed = (err) => {
if (err) {
reject(err);
}
else {
resolve(hasCancelled);
}
};
me.onCancelling(() => hasCancelled = true);
let workflow = Workflows.create();
afterDeployedOperations.forEach((currentOperation, i) => {
workflow.next((ctx) => {
return new Promise((res, rej) => {
let operationName = deploy_operations.getOperationName(currentOperation);
me.outputChannel.append(`[AFTER DEPLOY #${i + 1}] '${operationName}' `);
if (hasCancelled) {
ctx.finish();
}
else {
me.handleCommonDeployOperation(currentOperation, deploy_contracts.DeployOperationKind.After, files, target).then((handled) => {
if (handled) {
me.outputChannel.appendLine(i18.t('deploy.operations.finished'));
}
else {
me.outputChannel.appendLine(i18.t('deploy.operations.unknownType', currentOperation.type));
}
res();
}).catch((err) => {
me.outputChannel.appendLine(i18.t('deploy.operations.failed', err));
rej(err);
});
}
});
});
});
if (!hasCancelled) {
workflow.start().then(() => {
completed(null);
}).catch((e) => {
completed(e);
});
}
});
}
/**
* Returns all targets from config.
*/
get allTargetsFromConfig() {
return this._allTargets;
}
/**
* Invokes 'before deploy' operations for a target.
*
* @param {string[]} files The files to deploy.
* @param {deploy_contracts.DeployTarget} target The target.
*
* @return {Promise<boolean>} The promise.
*/
beforeDeploy(files, target) {
let me = this;
return new Promise((resolve, reject) => {
let beforeDeployOperations = deploy_helpers.asArray(target.beforeDeploy)
.filter(x => x);
let hasCancelled = false;
let completed = (err) => {
if (err) {
reject(err);
}
else {
resolve(hasCancelled);
}
};
me.onCancelling(() => hasCancelled = true);
let workflow = Workflows.create();
beforeDeployOperations.forEach((currentOperation, i) => {
workflow.next((ctx) => {
return new Promise((res, rej) => {
let operationName = deploy_operations.getOperationName(currentOperation);
me.outputChannel.append(`[BEFORE DEPLOY #${i + 1}] '${operationName}' `);
if (hasCancelled) {
ctx.finish();
}
else {
me.handleCommonDeployOperation(currentOperation, deploy_contracts.DeployOperationKind.Before, files, target).then((handled) => {
if (handled) {
me.outputChannel.appendLine(i18.t('deploy.operations.finished'));
}
else {
me.outputChannel.appendLine(i18.t('deploy.operations.unknownType', currentOperation.type));
}
res();
}).catch((err) => {
me.outputChannel.appendLine(i18.t('deploy.operations.failed', err));
rej(err);
});
}
});
});
});
if (!hasCancelled) {
workflow.start().then(() => {
completed(null);
}).catch((e) => {
completed(e);
});
}
});
}
/**
* Changes a switch target.
*/
changeSwitch() {
return __awaiter(this, arguments, void 0, function* () {
return yield deploy_switch.changeSwitch
.apply(this, arguments);
});
}
/**
* Clears the output on startup depending on the current configuration.
*/
clearOutputOrNot() {
if (deploy_helpers.toBooleanSafe(this.config.clearOutputOnStartup)) {
this.outputChannel.clear();
}
}
/**
* Compares a local file with a version from a target.
*
* @param {any} [uri] The URI of the file.
*
* @return {Promise<any>} The promise.
*/
compareFiles(uri) {
let me = this;
return new Promise((resolve, reject) => {
let completed = deploy_helpers.createSimplePromiseCompletedAction(resolve, reject);
let targets = this.getTargets()
.filter(x => !deploy_helpers.toBooleanSafe(x.isHidden));
if (targets.length < 1) {
vscode.window.showWarningMessage(i18.t('targets.noneDefined'));
return;
}
let path;
if (uri && uri.fsPath) {
path = uri.fsPath;
}
else {
let currentEditor = vscode.window.activeTextEditor;
if (currentEditor) {
let currentDocument = currentEditor.document;
if (currentDocument) {
path = currentDocument.fileName;
}
}
}
if (deploy_helpers.isEmptyString(path)) {
completed();
return;
}
let startDownlods = (t, files) => {
let type = deploy_helpers.parseTargetType(t.type);
let matchIngPlugins = me.pluginsWithContextes.filter(x => {
return !type ||
(x.plugin.__type === type && deploy_helpers.toBooleanSafe(x.plugin.canPull) && x.plugin.downloadFile);
});
if (matchIngPlugins.length > 0) {
let nextPlugin;
nextPlugin = () => {
if (matchIngPlugins.length < 1) {
completed();
return; // we have finished
}
let filesTODO = files.map(x => x);
let mp = matchIngPlugins.shift();
let p = mp.plugin;
let nextFile = () => {
if (filesTODO.length < 1) {
nextPlugin();
return;
}
let f = filesTODO.shift();
let diffFinished = (err) => {
if (err) {
completed(err);
}
else {
nextFile();
}
};
try {
let doDiff = (downloadedData) => {
if (!downloadedData) {
downloadedData = Buffer.alloc(0);
}
try {
// save downloaded data
// to temp file
TMP.tmpName({
keep: true,
prefix: 'vsd-',
postfix: Path.extname(f),
}, (err, tmpPath) => {
if (err) {
diffFinished(err);
}
else {
FS.writeFile(tmpPath, downloadedData, (err) => {
if (err) {
diffFinished(err);
}
else {
try {
let realtivePath = deploy_helpers.toRelativePath(f);
if (false === realtivePath) {
realtivePath = f;
}
let titleSuffix = deploy_helpers.toStringSafe(t.name).trim();
let windowTitle = `[vs-deploy] Diff '${realtivePath}'`;
if ('' === titleSuffix) {
titleSuffix = deploy_helpers.normalizeString(t.type);
}
if ('' !== titleSuffix) {
windowTitle += ` (${titleSuffix})`;
}
vscode.commands.executeCommand('vscode.diff', vscode.Uri.file(tmpPath), vscode.Uri.file(f), windowTitle).then(() => {
diffFinished(null);
}, (err) => {
diffFinished(err);
});
}
catch (e) {
diffFinished(e);
}
}
});
}
});
}
catch (e) {
diffFinished(e);
}
};
// download data
let downloadResult = p.downloadFile(f, t);
if (downloadResult) {
if (Buffer.isBuffer(downloadResult)) {
doDiff(downloadResult);
}
else {
downloadResult.then((data) => {
doDiff(data);
}, (err) => {
diffFinished(err);
});
}
}
else {
doDiff();
}
}
catch (e) {
diffFinished(e);
}
};
nextFile(); // start with first file
};
nextPlugin(); // start with first plugin
}
else {
// no matching plugin found
if (type) {
vscode.window.showWarningMessage(i18.t('compare.noPluginsForType', type));
}
else {
vscode.window.showWarningMessage(i18.t('compare.noPlugins'));
}
}
}; // startDownlods()
let selectTarget = (files) => {
// select the target /
// source from where to download from
let fileQuickPicks = targets.map((x, i) => deploy_helpers.createTargetQuickPick(x, i, me.getValues()));
if (fileQuickPicks.length > 1) {
vscode.window.showQuickPick(fileQuickPicks, {
placeHolder: i18.t('compare.selectSource'),
}).then((item) => {
if (item) {
startDownlods(item.target, files);
}
}, (err) => {
completed(err);
});
}
else {
// auto select
startDownlods(fileQuickPicks[0].target, files);
}
}; // selectTarget()
// first check if file
FS.lstat(path, (err, stats) => {
if (err) {
completed(i18.t('compare.failed', path, err));
}
else {
if (stats.isFile()) {
selectTarget([path]);
}
else if (stats.isDirectory()) {
Glob('**', {
absolute: true,
cwd: path,
dot: true,
ignore: [],
nodir: true,
root: path,
}, (e, files) => {
if (e) {
completed(i18.t('compare.failed', path, e));
}
else {
selectTarget(files);
}
});
}
else {
// no file
completed(i18.t('isNo.file', path));
}
}
});
});
}
/**
* Gets the current configuration.
*/
get config() {
return this._config;
}
/**
* Gets the extension context.
*/
get context() {
return this._CONTEXT;
}
/**
* Deploys a file.
*
* @param {string} file The path of the file to deploy.
*/
deployFile(file) {
let me = this;
let targets = this.getTargets()
.filter(x => !deploy_helpers.toBooleanSafe(x.isHidden));
if (targets.length < 1) {
vscode.window.showWarningMessage(i18.t('targets.noneDefined'));
return;
}
let quickPicks = targets.map((x, i) => deploy_helpers.createFileQuickPick(file, x, i, me.getValues()));
let deploy = (item) => {
try {
if (item) {
let showError = (err, type) => {
vscode.window.showErrorMessage(i18.t(`deploy.${type}.failed`, file, err));
};
me.beforeDeploy([file], item.target).then((canceled) => {
if (canceled) {
return;
}
me.deployFileTo(file, item.target).then((canceled) => {
if (canceled) {
return;
}
// DO NOT invoke me.afterDeployment()
// this is done by me.deployFileTo()!
}).catch((err) => {
showError(err, 'file');
}); // deploy
}).catch((err) => {
showError(err, 'before');
}); // beforeDeploy
}
}
catch (e) {
vscode.window.showErrorMessage(i18.t('deploy.file.failed', file, e));
}
};
if (quickPicks.length > 1 || deploy_helpers.toBooleanSafe(me.config.alwaysShowTargetList)) {
vscode.window.showQuickPick(quickPicks, {
placeHolder: i18.t('targets.select'),
}).then((item) => {
deploy(item);
});
}
else {
// auto select
deploy(quickPicks[0]);
}
}
/**
* Deploys a file or folder.
*
* @param {any} [uri] The URI of the file / folder to deploy.
*/
deployFileOrFolder(uri) {
let me = this;
let path;
if (uri && uri.fsPath) {
path = uri.fsPath;
}
else {
let currentEditor = vscode.window.activeTextEditor;
if (currentEditor) {
let currentDocument = currentEditor.document;
if (currentDocument) {
path = currentDocument.fileName;
}
}
}
if (deploy_helpers.isEmptyString(path)) {
return;
}
let showError = (err) => {
vscode.window.showErrorMessage(i18.t('deploy.fileOrFolder.failed', path, err));
};
// check if file or folder
FS.lstat(path, (err, stats) => {
if (err) {
showError(err);
return;
}
try {
if (stats.isDirectory()) {
me.deployFolder(path); // folder
}
else if (stats.isFile()) {
me.deployFile(path); // file
}
else {
showError(new Error(i18.t('isNo.validItem', path)));
}
}
catch (e) {
showError(e);
}
});
}
/**
* Deploys a file to a target.
*
* @param {string} file The file to deploy.
* @param {deploy_contracts.DeployTarget} target The target to deploy to.
*
* @return {Promise<boolean>} The promise.
*/
deployFileTo(file, target) {
let me = this;
return new Promise((resolve, reject) => {
let hasCancelled = false;
let completed = (err) => {
if (err) {
reject(err);
}
else {
resolve(hasCancelled);
}
};
if (me.isFileIgnored(file)) {
if (deploy_helpers.toBooleanSafe(me.config.showWarningIfIgnored, true)) {
// show warning
vscode.window.showWarningMessage(i18.t('deploy.file.isIgnored', file));
}
hasCancelled = true;
completed(null);
return;
}
me.onCancelling(() => hasCancelled = true);
try {
me.hideAfterDeploymentStatusBarItem();
let type = deploy_helpers.parseTargetType(target.type);
let matchIngPlugins = me.pluginsWithContextes.filter(x => {
return !type ||
(x.plugin.__type === type && x.plugin.deployFile);
});
let relativePath = deploy_helpers.toRelativePath(file);
if (false === relativePath) {
relativePath = file;
}
if (matchIngPlugins.length > 0) {
let deployNextPlugin;
deployNextPlugin = () => {
if (matchIngPlugins.length < 1) {
completed();
return;
}
if (hasCancelled) {
completed();
return;
}
let cancelCommand;
let currentPluginWithContext = matchIngPlugins.shift();
let contextToUse = deploy_plugins.createPluginContext(currentPluginWithContext.context);
let currentPlugin = currentPluginWithContext.plugin;
let statusBarItem;
let cleanUps = () => {
deploy_helpers.tryDispose(cancelCommand);
deploy_helpers.tryDispose(statusBarItem);
deploy_helpers.tryDispose(contextToUse);
};
let deployPlugin = () => {
try {
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
statusBarItem.color = '#ffffff';
statusBarItem.text = i18.t('deploy.button.prepareText');
statusBarItem.tooltip = i18.t('deploy.button.tooltip');
let cancelCommandName = 'extension.deploy.cancelFile' + (nextCancelDeployFileCommandId--);
cancelCommand = vscode.commands.registerCommand(cancelCommandName, () => {
if (hasCancelled) {
return;
}
hasCancelled = true;
try {
contextToUse.emit(deploy_contracts.EVENT_CANCEL_DEPLOY);
}
catch (e) {
me.log(i18.t('errors.withCategory', 'Deployer.deployFileTo().cancel', e));
}
statusBarItem.text = i18.t('deploy.button.cancelling');
statusBarItem.tooltip = i18.t('deploy.button.cancelling');
});
statusBarItem.command = cancelCommandName;
let showResult = (err) => {
let afterDeployButtonMsg = 'Deployment finished.';
try {
cleanUps();
let targetExpr = deploy_helpers.toStringSafe(target.name).trim();
let resultMsg;
if (err) {
if (hasCancelled) {
resultMsg = i18.t('deploy.canceledWithErrors');
}
else {
resultMsg = i18.t('deploy.finishedWithErrors');
}
}
else {
if (deploy_helpers.toBooleanSafe(me.config.showPopupOnSuccess, true)) {
if (targetExpr) {
vscode.window.showInformationMessage(i18.t('deploy.file.succeededWithTarget', file, targetExpr));
}
else {
vscode.window.showInformationMessage(i18.t('deploy.file.succeeded', file));
}
}
if (hasCancelled) {
resultMsg = i18.t('deploy.canceled');
}
else {
resultMsg = i18.t('deploy.finished2');
me.afterDeployment([file], target).catch((err) => {
vscode.window.showErrorMessage(i18.t('deploy.after.failed', err));
});
}
}
if (resultMsg) {
afterDeployButtonMsg = resultMsg;
me.outputChannel.appendLine(resultMsg);
}
}
finally {
me.showStatusBarItemAfterDeployment(afterDeployButtonMsg, [file], err ? [] : [file], err ? [file] : []);
completed(err);
}
};
try {
statusBarItem.show();
currentPlugin.deployFile(file, target, {
context: contextToUse,
onBeforeDeploy: (sender, e) => {
let destination = deploy_helpers.toStringSafe(e.destination);
let targetName = deploy_helpers.toStringSafe(e.target.name);
me.outputChannel.appendLine('');
let deployMsg;
if (targetName) {
targetName = ` ('${targetName}')`;
}
if (destination) {
deployMsg = i18.t('deploy.file.deployingWithDestination', file, destination, targetName);
}
else {
deployMsg = i18.t('deploy.file.deploying', file, targetName);
}
me.outputChannel.append(deployMsg);
if (deploy_helpers.toBooleanSafe(me.config.openOutputOnDeploy, true)) {
me.outputChannel.show();
}
statusBarItem.text = i18.t('deploy.button.text');
},
onCompleted: (sender, e) => {
if (e.error) {
me.outputChannel.appendLine(i18.t('failed', e.error));
}
else {
me.outputChannel.appendLine(i18.t('ok'));
}
hasCancelled = hasCancelled || e.canceled;
showResult(e.error);
}
});
}
catch (e) {
showResult(e);
}
}
catch (e) {
cleanUps();
completed(e);
}
};
let checkForNewer = () => {
if (deploy_helpers.toBooleanSafe(target.checkBeforeDeploy)) {
deploy_diff.checkForNewerFiles.apply(me, [[file], target, currentPlugin]).then((startDeploy) => {
if (startDeploy) {
deployPlugin();
}
else {
deployNextPlugin();
}
}).catch((e) => {
completed(e);
});
}
else {
deployPlugin();
}
};
if (deploy_helpers.toBooleanSafe(target.diffBeforeDeploy)) {
if (deploy_helpers.toBooleanSafe(currentPlugin.canPull) && currentPlugin.downloadFile) {
// make a diff and ask the
// if (s)he really wants to deploy
me.compareFiles(vscode.Uri.file(file)).then(() => {
// [BUTTON] yes
let yesBtn = new deploy_objects.SimplePopupButton();
yesBtn.action = () => {
deployPlugin(); // user wants to deploy
};
yesBtn.title = i18.t('yes');
vscode.window
.showWarningMessage(i18.t('deploy.startQuestion'), yesBtn)
.then((item) => {
if (!item || !item.action) {
return;
}
item.action();
});
}).catch((err) => {
completed(err);
});
}
else {
checkForNewer();
}
}
else {
checkForNewer();
}
};
deployNextPlugin();
}
else {
if (type) {
vscode.window.showWarningMessage(i18.t('deploy.noPluginsForType', type));
}
else {
vscode.window.showWarningMessage(i18.t('deploy.noPlugins'));
}
completed();
}
}
catch (e) {
completed(e);
}
});
}
/**
* Deploys a folder.
*
* @param {string} dir The path of the folder to deploy.
*/
deployFolder(dir) {
let me = this;
dir = Path.resolve(dir);
let filesToDeploy = Glob.sync('**', {
absolute: true,
cwd: dir,
dot: true,
ignore: [],
nodir: true,
root: dir,
});
let targets = this.getTargets()
.filter(x => !deploy_helpers.toBooleanSafe(x.isHidden));
if (targets.length < 1) {
vscode.window.showWarningMessage(i18.t('targets.noneDefined'));
return;
}
// start deploy the folder
// by selected target
let deploy = (t) => {
me.beforeDeploy(filesToDeploy, t).then((canceled) => {
if (canceled) {
return;
}
if (filesToDeploy.length < 1) {
vscode.window.showWarningMessage(i18.t('deploy.noFiles'));
return;
}
me.deployWorkspaceTo(filesToDeploy, t).then(() => {
//TODO
}).catch((err) => {
vscode.window.showErrorMessage(i18.t('deploy.folder.failed', dir, err));
});
}).catch((err) => {
vscode.window.showErrorMessage(i18.t('deploy.before.failed', err));
});
};
// select the target
let fileQuickPicks = targets.map((x, i) => deploy_helpers.createTargetQuickPick(x, i, me.getValues()));
if (fileQuickPicks.length > 1) {
vscode.window.showQuickPick(fileQuickPicks, {
placeHolder: i18.t('deploy.folder.selectTarget'),
}).then((item) => {
if (item) {
deploy(item.target);
}
});
}
else {
// auto select
deploy(fileQuickPicks[0].target);
}
}
/**
* Deploys files of the workspace.
*
* @param {deploy_contracts.DeployPackage|deploy_contracts.DeployPackage[]} [packagesToDeploy] The package(s) to deploy.
* @param {deploy_contracts.DeployTarget|deploy_contracts.DeployTarget[]} [targetsToDeployTo] The target(s) to deploy to.
*
* @return {Promise<number>} The promise.
*/
deployWorkspace(packagesToDeploy, targetsToDeployTo) {
let me = this;
return new Promise((resolve, reject) => {
let completed = (err, code) => {
if (err) {
reject(err);
}
else {
resolve(code);
}
};
let packages = deploy_helpers.asArray(packagesToDeploy).filter(x => x);
if (packages.length < 1) {
// no explicit packages found in method arguments
// so read packages from config
packages = me.getPackages()
.filter(x => !deploy_helpers.toBooleanSafe(x.isHidden) &&
deploy_helpers.toBooleanSafe(x.showForDeploy, true));
}
if (packages.length < 1) {
vscode.window.showWarningMessage(i18.t('packages.noneDefined'));
completed(null, 1); // no packages found
return;
}
let packageQuickPicks = packages.map((x, i) => deploy_helpers.createPackageQuickPick(x, i, me.getValues()));
let selectTarget = (pkg) => {
if (!pkg) {
completed(null, 3); // aborted
return;
}
let targets = deploy_helpers.asArray(targetsToDeployTo).filter(x => x);
if (targets.length < 1) {
// no explicit targets found in method arguments
// so read targets from package
targets = me.filterTargetsByPackage(pkg)
.filter(x => !deploy_helpers.toBooleanSafe(x.isHidden));
}
if (targets.length < 1) {
vscode.window.showWarningMessage(i18.t('targets.noneDefined'));
completed(null, 4); // no target found
return;
}
let packageName = deploy_helpers.toStringSafe(pkg.name);
let filesToDeploy = deploy_helpers.getFilesOfPackage(pkg, me.useGitIgnoreStylePatternsInFilter(pkg));
let deploy = (t) => {
try {
if (!t) {
completed(null, 6); // aborted
return;
}
let targetName = deploy_helpers.toStringSafe(t.name);
me.outputChannel.appendLine('');
let deployMsg;
if (targetName) {
deployMsg = i18.t('deploy.workspace.deployingWithTarget', packageName, targetName);
}
else {
deployMsg = i18.t('deploy.workspace.deploying', packageName);
}
me.outputChannel.appendLine(deployMsg);
if (deploy_helpers.toBooleanSafe(me.config.openOutputOnDeploy, true)) {
me.outputChannel.show();
}
me.beforeDeploy(filesToDeploy, t).then((canceled) => {
if (canceled) {
completed(null, 7); // canceled
return;
}
filesToDeploy = deploy_helpers.getFilesOfPackage(pkg, me.useGitIgnoreStylePatternsInFilter(pkg)); // now update file list
if (filesToDeploy.length < 1) {
vscode.window.showWarningMessage(i18.t('deploy.noFiles'));
completed(null, 8); // no files
return;
}
me.deployWorkspaceTo(filesToDeploy, t).then(() => {
completed(null, 0); // anthing finished
}).catch((err) => {
completed(new Error(i18.t('deploy.workspace.failedWithCategory', 2, err)));
});
}).catch((err) => {
completed(new Error(i18.t('deploy.before.failed', err)));
});
}
catch (e) {
completed(new Error(i18.t('deploy.workspace.failedWithCategory', 1, e)));
}
};
let targetsOfPackage = me.getTargetsFromPackage(pkg);
if (targetsOfPackage.length < 1) {
// no explicit targets
let fileQuickPicks = targets.map((x, i) => deploy_helpers.createTargetQuickPick(x, i, me.getValues()));
if (fileQuickPicks.length > 1 || deploy_helpers.toBooleanSafe(me.config.alwaysShowTargetList)) {
vscode.window.showQuickPick(fileQuickPicks, {
placeHolder: i18.t('deploy.workspace.selectTarget'),
}).then((item) => {
if (item) {
deploy(item.target);
}
else {
completed(null, 5); // aborted
}
}, (err) => {
completed(err);
});
}
else {
// auto select
deploy(fileQuickPicks[0].target);
}
}
else {
// we have explicit defined targets here
if (1 === targetsOfPackage.length) {
deploy(targetsOfPackage[0]); // deploy the one and only
}
else {
// create a virtual "batch" target
// for the underlying "real" targets
let virtualPkgName;
if (packageName) {
virtualPkgName = i18.t('deploy.workspace.virtualTargetNameWithPackage', packageName);
}
else {
virtualPkgName = i18.t('deploy.workspace.virtualTargetName');
}
let batchTarget = {
type: 'batch',
name: virtualPkgName,
targets: targetsOfPackage.map(x => x.name),
};
deploy(batchTarget);
}
}
};
if (packageQuickPicks.length > 1 || deploy_helpers.toBooleanSafe(me.config.alwaysShowPackageList)) {
vscode.window.showQuickPick(packageQuickPicks, {
placeHolder: i18.t('deploy.workspace.selectPackage'),
}).then((item) => {
if (item) {
selectTarget(item.package);
}
else {
completed(null, 2); // aborted
}
}, (err) => {
completed(err);
});
}
else {
// auto select
selectTarget(packageQuickPicks[0].package);
}
});
}
/**
* Deploys files of the workspace to a target.
*
* @param {string[]} files The files to deploy.
* @param {deploy_contracts.DeployTarget} target The target.
*
* @returns {Promise<boolean>} The promise.
*/
deployWorkspaceTo(files, target) {
let me = this;
let nameOfTarget = deploy_helpers.normalizeString(target.name);
if (files) {
files = files.filter(f => !me.isFileIgnored(f));
}
return new Promise((resolve, reject) => {
let hasCancelled = false;
let completed = (err) => {
delete me._WORKSPACE_IN_PROGRESS[nameOfTarget];
if (err) {
reject(err);
}
else {