UNPKG

vs-deploy

Version:

Commands for deploying files of your workspace to a destination.

1,086 lines (1,085 loc) 196 kB
"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 {