diff --git a/CHANGELOG.md b/CHANGELOG.md index fbe48fd..3b82f7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,18 @@ [![Share via Facebook](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Facebook.png)](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded"e=vscode-deploy-reloaded) [![Share via Twitter](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Twitter.png)](https://twitter.com/intent/tweet?source=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded&text=vscode-deploy-reloaded:%20https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded&via=mjkloubert) [![Share via Google+](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Google+.png)](https://plus.google.com/share?url=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded) [![Share via Pinterest](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Pinterest.png)](https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded&media=https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/demo1.gif&description=Recoded%20version%20of%20Visual%20Studio%20Code%20extension%20%27vs-deploy%27%2C%20which%20provides%20commands%20to%20deploy%20files%20to%20one%20or%20more%20destinations.) [![Share via Reddit](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Reddit.png)](https://www.reddit.com/submit?url=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded&title=vscode-deploy-reloaded) [![Share via LinkedIn](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/LinkedIn.png)](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded&title=vscode-deploy-reloaded&summary=Recoded%20version%20of%20Visual%20Studio%20Code%20extension%20%27vs-deploy%27%2C%20which%20provides%20commands%20to%20deploy%20files%20to%20one%20or%20more%20destinations.&source=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded) [![Share via Wordpress](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Wordpress.png)](https://wordpress.com/press-this.php?u=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded"e=vscode-deploy-reloaded&s=Recoded%20version%20of%20Visual%20Studio%20Code%20extension%20%27vs-deploy%27%2C%20which%20provides%20commands%20to%20deploy%20files%20to%20one%20or%20more%20destinations.&i=https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/demo1.gif) [![Share via Email](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/share/Email.png)](mailto:?subject=vscode-deploy-reloaded&body=Recoded%20version%20of%20Visual%20Studio%20Code%20extension%20'vs-deploy'%2C%20which%20provides%20commands%20to%20deploy%20files%20to%20one%20or%20more%20destinations.:%20https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmkloubert.vscode-deploy-reloaded) +## 0.72.0 (April 13th, 2018; file explorer operations) + +* can list or remove directories on [targets](https://github.com/mkloubert/vscode-deploy-reloaded/wiki#targets-), from file explorer now + +![Demo List and remove diretories from file explorer](https://raw.githubusercontent.com/mkloubert/vscode-deploy-reloaded/master/img/demo29.gif) + ## 0.71.0 (April 13th, 2018; create directories recursively) -* fixed and improved creation of directories recursively in [sftp targets](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and [ftp targets](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp) -* fixed cancellation of operation, when using things like [azureblob](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_azureblob), [dropbox](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_dropbox), [ftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp), [s3bucket](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_s3bucket), [sftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and/or [slack](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_slack) targets +* fixed and improved creation of directories recursively in [sftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and [ftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp) targets +* fixed cancellation of operations, when using things like [azureblob](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_azureblob), [dropbox](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_dropbox), [ftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp), [s3bucket](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_s3bucket), [sftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and/or [slack](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_slack) targets * improved displaying file paths in output when running a deploy operation -* added `supportsDeepDirectoryCreation` settings for [sftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and [ftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp) target, which indicate if a server supports creating directories recursively or not ... if so, you should set this to `(true)`, which can help increasing speed, when uploading files +* added `supportsDeepDirectoryCreation` settings for [sftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_sftp) and [ftp](https://github.com/mkloubert/vscode-deploy-reloaded/wiki/target_ftp) targets, which indicate, if a server supports creating directories recursively or not ... if so, you should set this to `(true)`, which can help increasing speed, when uploading files * updated the following [npm](https://www.npmjs.com/) modules: * [aws-sdk](https://www.npmjs.com/package/aws-sdk) `2.224.1` * [uglify-js](https://www.npmjs.com/package/uglify-js) `3.3.21` diff --git a/img/demo29.gif b/img/demo29.gif new file mode 100644 index 0000000..f5764dc Binary files /dev/null and b/img/demo29.gif differ diff --git a/package-lock.json b/package-lock.json index 8c9d916..d53e399 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vscode-deploy-reloaded", - "version": "0.71.0", + "version": "0.72.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1da4a41..b85a71e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-deploy-reloaded", "displayName": "Deploy (Reloaded)", "description": "Deploys files of a workspace to a destination.", - "version": "0.71.0", + "version": "0.72.0", "publisher": "mkloubert", "engines": { "vscode": "^1.22.0" diff --git a/src/commands.ts b/src/commands.ts index bd66b38..5f5051d 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -19,12 +19,15 @@ import * as deploy_contracts from './contracts'; import * as deploy_delete from './delete'; import * as deploy_deploy from './deploy'; import * as deploy_helpers from './helpers'; +import * as deploy_list from './list'; import * as deploy_log from './log'; +import * as deploy_plugins from './plugins'; import * as deploy_pull from './pull'; import * as deploy_targets from './targets'; import * as deploy_values from './values'; import * as deploy_workspaces from './workspaces'; import * as Enumerable from 'node-enumerable'; +import * as FSExtra from 'fs-extra'; import * as i18 from './i18'; import * as Path from 'path'; import * as vscode from 'vscode'; @@ -542,7 +545,30 @@ export async function handleFilesAndFolders( } }; - const QUICK_PICKS: deploy_contracts.ActionQuickPick[] = [ + const QUICK_PICKS: deploy_contracts.ActionQuickPick[] = []; + const SHOW_QUICK_PICKS = async () => { + const SELECTED_ITEM = await vscode.window.showQuickPick( + QUICK_PICKS + ); + + if (SELECTED_ITEM) { + await Promise.resolve( + SELECTED_ITEM.action() + ); + } + }; + + const ADD_SEPARATOR = () => { + QUICK_PICKS.push({ + action: () => { + SHOW_QUICK_PICKS(); + }, + label: '-', + description: '', + }); + }; + + QUICK_PICKS.push( { action: async () => { await INVOKE_TARGET_ACTION(async (target, files) => { @@ -618,16 +644,221 @@ export async function handleFilesAndFolders( label: '$(trashcan) ' + i18.t(`DELETE.currentFileOrFolder.${uriType}.label`), description: i18.t(`DELETE.currentFileOrFolder.${uriType}.description`), }, - ]; - - const SELECTED_ITEM = await vscode.window.showQuickPick( - QUICK_PICKS ); - if (SELECTED_ITEM) { - await Promise.resolve( - SELECTED_ITEM.action() - ); + + if (1 === filesAndFolders.length) { + const LOCAL_ITEM = filesAndFolders[0]; + + if ('folder' === uriType) { + const TARGETS_CAN_LIST = deploy_helpers.from( ACTIVE_TARGETS ).where(t => { + return t.__workspace + .getListPlugins(t).length > 0; + }).toArray(); + const TARGETS_CAN_REMOVE_FOLDER = deploy_helpers.from( ACTIVE_TARGETS ).where(t => { + return t.__workspace + .getRemoveFolderPlugins(t).length > 0; + }).toArray(); + + if (TARGETS_CAN_LIST.length > 0 || TARGETS_CAN_REMOVE_FOLDER.length > 0) { + ADD_SEPARATOR(); + } + + if (TARGETS_CAN_LIST.length > 0) { + QUICK_PICKS.push( + // list directory + { + action: async () => { + const SELECTED_TARGET = await deploy_targets.showTargetQuickPick( + context, TARGETS_CAN_LIST, + { + placeHolder: i18.t('targets.selectTarget'), + } + ); + + if (SELECTED_TARGET) { + const WORKSPACE = SELECTED_TARGET.__workspace; + + const RELATIVE_PATH = WORKSPACE.toRelativePath(LOCAL_ITEM); + if (false !== RELATIVE_PATH) { + await deploy_helpers.applyFuncFor( + deploy_list.listDirectory, WORKSPACE + )(SELECTED_TARGET, + deploy_helpers.normalizePath(RELATIVE_PATH)); + } + } + }, + label: '$(list-ordered) ' + i18.t(`listDirectory.currentFileOrFolder.label`), + description: i18.t(`listDirectory.currentFileOrFolder.description`), + } + ); + } + + if (TARGETS_CAN_REMOVE_FOLDER.length > 0) { + QUICK_PICKS.push( + // remove folder + { + action: async () => { + const SELECTED_TARGET = await deploy_targets.showTargetQuickPick( + context, TARGETS_CAN_REMOVE_FOLDER, + { + placeHolder: i18.t('targets.selectTarget'), + } + ); + + if (!SELECTED_TARGET) { + return; + } + + const MAPPING_SCOPE_DIRS = await deploy_targets.getScopeDirectoriesForTargetFolderMappings( + SELECTED_TARGET + ); + const TARGET_NAME = deploy_targets.getTargetName(SELECTED_TARGET); + const WORKSPACE = SELECTED_TARGET.__workspace; + + const NAME_AND_PATH = deploy_targets.getNameAndPathForFileDeployment(SELECTED_TARGET, LOCAL_ITEM, + MAPPING_SCOPE_DIRS); + if (false === NAME_AND_PATH) { + return; + } + + const PLUGINS = WORKSPACE.getRemoveFolderPlugins(SELECTED_TARGET); + + if (PLUGINS.length < 1) { + return; + } + + const MAPPED_PATH = '/' + deploy_helpers.normalizePath( + deploy_helpers.normalizePath(NAME_AND_PATH.path) + + '/' + + deploy_helpers.normalizePath(NAME_AND_PATH.name) + ); + + const SELECTED_ITEM = await vscode.window.showWarningMessage( + WORKSPACE.t('listDirectory.currentFileOrFolder.removeFolder.askBeforeRemove', + MAPPED_PATH + ), + { + isCloseAffordance: true, + title: WORKSPACE.t('no'), + value: 0, + }, + { + title: WORKSPACE.t('yes'), + value: 1, + }, + { + title: WORKSPACE.t('listDirectory.currentFileOrFolder.removeFolder.yesWithLocalFolder'), + value: 2, + } + ); + + if (!SELECTED_ITEM || 0 === SELECTED_ITEM.value) { + return; + } + + WORKSPACE.output.appendLine(''); + + const WITH_LOCAL_FOLDER = 2 === SELECTED_ITEM.value; + + await deploy_helpers.withProgress(async (progress) => { + let watch: deploy_helpers.StopWatch; + const START_WATCH = () => watch = deploy_helpers.startWatch(); + const STOP_WATCH = () => { + if (watch) { + WORKSPACE.output.appendLine(` [${watch.stop()} ms]`); + } + + watch = null; + }; + + while (PLUGINS.length > 0) { + const PI = PLUGINS.shift(); + + const FOLDER_TO_REMOVE = new deploy_plugins.SimpleFolderToRemove( + WORKSPACE, + LOCAL_ITEM, + NAME_AND_PATH, + ); + + FOLDER_TO_REMOVE.onBeforeRemove = async (destination?) => { + const NOW = deploy_helpers.now(); + + if (arguments.length < 1) { + destination = NAME_AND_PATH.path; + } + destination = `${deploy_helpers.toStringSafe(destination)} (${TARGET_NAME})`; + + const PROGRESS_MSG = `💣 ` + + WORKSPACE.t('listDirectory.currentFileOrFolder.removeFolder.removing', + MAPPED_PATH); + + WORKSPACE.output.append( + `[${NOW.format( WORKSPACE.t('time.timeWithSeconds') )}] ` + + PROGRESS_MSG + ' ' + ); + + if (progress.cancellationToken.isCancellationRequested) { + WORKSPACE.output.appendLine(`✖️`); + } + else { + START_WATCH(); + } + }; + FOLDER_TO_REMOVE.onRemoveCompleted = async (err?, deleteLocal?) => { + if (err) { + WORKSPACE.output.append(`🔥: '${ deploy_helpers.toStringSafe(err) }'`); + } + else { + let showOK = true; + + if (WITH_LOCAL_FOLDER) { + if (deploy_helpers.toBooleanSafe(deleteLocal, true)) { + try { + await FSExtra.remove( LOCAL_ITEM ); + } + catch (e) { + showOK = false; + + WORKSPACE.output.append(`⚠️: '${deploy_helpers.toStringSafe(e)}'`); + } + } + } + + if (showOK) { + WORKSPACE.output.append(`✅`); + } + } + + STOP_WATCH(); + }; + + const CTX: deploy_plugins.RemoveFoldersContext = { + cancellationToken: null, + isCancelling: null, + folders: [ + FOLDER_TO_REMOVE + ], + target: SELECTED_TARGET, + }; + + await PI.removeFolders(CTX); + } + }, { + cancellable: true, + location: vscode.ProgressLocation.Notification, + title: `💣 ` + WORKSPACE.t('listDirectory.currentFileOrFolder.removeFolder.removing', + MAPPED_PATH), + }); + }, + label: '$(trashcan) ' + i18.t(`listDirectory.currentFileOrFolder.removeFolder.label`), + description: i18.t(`listDirectory.currentFileOrFolder.removeFolder.description`), + } + ); + } + } } + + await SHOW_QUICK_PICKS(); } catch (e) { deploy_log.CONSOLE diff --git a/src/i18.ts b/src/i18.ts index afce037..f5869c6 100644 --- a/src/i18.ts +++ b/src/i18.ts @@ -287,6 +287,17 @@ export interface Translation { label?: string; }; currentDirectory?: string; + currentFileOrFolder?: { + description?: string; + label?: string; + removeFolder?: { + askBeforeRemove?: string; + description?: string; + label?: string; + removing?: string; + yesWithLocalFolder?: string; + }; + }; directoryIsEmpty?: string; errors?: { failed?: string; diff --git a/src/lang/de.ts b/src/lang/de.ts index e86662e..6844e81 100644 --- a/src/lang/de.ts +++ b/src/lang/de.ts @@ -282,6 +282,17 @@ export const translation: Translation = { label: "Pfad kopieren ...", }, currentDirectory: "Aktuelles Verzeichnis:{0:trim,surround,leading_space} ({1:trim,surround})", + currentFileOrFolder: { + description: "Zeigt den Inhalt dieses Verzeichnisses in einem Ziel an", + label: "Verzeichnis anzeigen ...", + removeFolder: { + askBeforeRemove: "Möchten Sie das Verzeichnis{0:trim,surround,leading_space} wirklich löschen?", + description: "Löscht das Verzeichnis samt Inhalt in einem Ziel", + label: "Gesamtes Verzeichnis löschen ...", + removing: "Lösche Verzeichnis{0:trim,surround,leading_space} ...", + yesWithLocalFolder: "JA inkl. lokalem Verzeichnis", + }, + }, directoryIsEmpty: "(Verzeichnis ist leer)", errors: { failed: "Konnte das Auflisten des Verzeichnisses{0:trim,surround,leading_space} ({1:trim,surround,leading_space}) nicht durchführen: {2:trim,surround,leading_space}", diff --git a/src/lang/en.ts b/src/lang/en.ts index e71ab60..905f881 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -282,6 +282,17 @@ export const translation: Translation = { label: "Copy path ...", }, currentDirectory: "Current directory:{0:trim,surround,leading_space} ({1:trim,surround})", + currentFileOrFolder: { + description: "Lists the items of that directory on a target", + label: "Show directory ...", + removeFolder: { + askBeforeRemove: "Do you really want to delete the folder{0:trim,surround,leading_space}?", + description: "Deletes the directory and all its content on a target", + label: "Delete complete folder ...", + removing: "Removing folder{0:trim,surround,leading_space} ...", + yesWithLocalFolder: "YES with local folder", + }, + }, directoryIsEmpty: "(directory is empty)", errors: { failed: "Could not list directory{0:trim,surround,leading_space} ({1:trim,surround,leading_space}): {2:trim,surround,leading_space}", diff --git a/src/list.ts b/src/list.ts index f32322b..62e12e3 100644 --- a/src/list.ts +++ b/src/list.ts @@ -314,7 +314,7 @@ export async function listDirectory(target: deploy_targets.Target, dir?: string) }, { cancellable: true, location: vscode.ProgressLocation.Notification, - title: `[${TARGET_NAME}]`, + title: `🔍 [${TARGET_NAME}]`, }); if (false === FILES_AND_FOLDERS) { @@ -658,8 +658,8 @@ export async function listDirectory(target: deploy_targets.Target, dir?: string) }, { cancellable: true, location: vscode.ProgressLocation.Notification, - title: ME.t('listDirectory.removeFolder.removing', - exportPath) + title: `💣 ` + ME.t('listDirectory.removeFolder.removing', + exportPath) }); }, @@ -974,13 +974,10 @@ async function removeFolder( target: deploy_targets.Target, dir: string, progress: deploy_helpers.ProgressContext, ) { - const WORKSPACE = target.__workspace; - - const PROGRESS_MSG = WORKSPACE.t('listDirectory.removeFolder.removing', - dir); + const TARGET_NAME = deploy_targets.getTargetName(target); + const WORKSPACE = target.__workspace; WORKSPACE.output.appendLine(''); - WORKSPACE.output.append(PROGRESS_MSG + ' '); try { const PLUGINS = WORKSPACE.getRemoveFolderPlugins(target); @@ -991,6 +988,16 @@ async function removeFolder( }); }; + let watch: deploy_helpers.StopWatch; + const START_WATCH = () => watch = deploy_helpers.startWatch(); + const STOP_WATCH = () => { + if (watch) { + WORKSPACE.output.appendLine(` [${watch.stop()} ms]`); + } + + watch = null; + }; + for (let i = 0; i < PLUGINS.length; i++) { if (progress.cancellationToken.isCancellationRequested) { break; @@ -998,24 +1005,59 @@ async function removeFolder( const P = PLUGINS[i]; - UPDATE_PROGRESS(PROGRESS_MSG); + const FOLDER_TO_REMOVE = new deploy_plugins.SimpleFolderToRemove( + WORKSPACE, + undefined, + { + name: deploy_helpers.normalizePath( + Path.basename(dir) + ), + path: deploy_helpers.normalizePath( + Path.dirname(dir) + ), + } + ); + + FOLDER_TO_REMOVE.onBeforeRemove = async (destination?) => { + const NOW = deploy_helpers.now(); + + if (arguments.length < 1) { + destination = FOLDER_TO_REMOVE.path; + } + destination = `${deploy_helpers.toStringSafe(destination)} (${TARGET_NAME})`; + + const PROGRESS_MSG = `💣 ` + + WORKSPACE.t('listDirectory.currentFileOrFolder.removeFolder.removing', + dir); + + WORKSPACE.output.append( + `[${NOW.format( WORKSPACE.t('time.timeWithSeconds') )}] ` + + PROGRESS_MSG + ' ' + ); + + UPDATE_PROGRESS( PROGRESS_MSG ); + + if (progress.cancellationToken.isCancellationRequested) { + WORKSPACE.output.appendLine(`✖️`); + } + else { + START_WATCH(); + } + }; + FOLDER_TO_REMOVE.onRemoveCompleted = async (err?, deleteLocal?) => { + if (err) { + WORKSPACE.output.append(`🔥: '${ deploy_helpers.toStringSafe(err) }'`); + } + else { + WORKSPACE.output.append(`✅`); + } + + STOP_WATCH(); + }; const CTX: deploy_plugins.RemoveFoldersContext = { cancellationToken: progress.cancellationToken, - folders: [ - new deploy_plugins.SimpleFolderToRemove( - WORKSPACE, - undefined, - { - name: deploy_helpers.normalizePath( - Path.basename(dir) - ), - path: deploy_helpers.normalizePath( - Path.dirname(dir) - ), - } - ) - ], + folders: [ FOLDER_TO_REMOVE ], isCancelling: undefined, target: target, }; @@ -1031,15 +1073,9 @@ async function removeFolder( await P.removeFolders(CTX); } - - WORKSPACE.output.appendLine(`✅`); } catch (e) { - if (progress.cancellationToken.isCancellationRequested) { - WORKSPACE.output.appendLine(`✖️`); - } - else { - WORKSPACE.output.appendLine(`🔥: '${ deploy_helpers.toStringSafe(e) }'`); - } + deploy_log.CONSOLE + .trace(e, 'list.removeFolder(1)'); } }