Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"onCommand:vscode-docker.containers.attachShell",
"onCommand:vscode-docker.containers.browse",
"onCommand:vscode-docker.containers.configureExplorer",
"onCommand:vscode-docker.containers.downloadFile",
"onCommand:vscode-docker.containers.inspect",
"onCommand:vscode-docker.containers.openFile",
"onCommand:vscode-docker.containers.prune",
Expand Down Expand Up @@ -128,6 +129,10 @@
"contributes": {
"menus": {
"commandPalette": [
{
"command": "vscode-docker.containers.downloadFile",
"when": "never"
},
{
"command": "vscode-docker.containers.openFile",
"when": "never"
Expand Down Expand Up @@ -381,6 +386,10 @@
"when": "view == dockerContainers && viewItem =~ /^(created|dead|exited|paused|terminated)Container$/i",
"group": "containers_1_general@5"
},
{
"command": "vscode-docker.containers.downloadFile",
"when": "view == dockerContainers && viewItem == containerFile"
},
{
"command": "vscode-docker.containers.openFile",
"when": "view == dockerContainers && viewItem == containerFile"
Expand Down Expand Up @@ -2212,6 +2221,11 @@
"dark": "resources/dark/settings.svg"
}
},
{
"command": "vscode-docker.containers.downloadFile",
"title": "%vscode-docker.commands.containers.downloadFile%",
"category": "%vscode-docker.commands.category.dockerContainers%"
},
{
"command": "vscode-docker.containers.inspect",
"title": "%vscode-docker.commands.containers.inspect%",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"vscode-docker.commands.containers.attachShell": "Attach Shell",
"vscode-docker.commands.containers.browse": "Open in Browser",
"vscode-docker.commands.containers.configureExplorer": "Configure Explorer...",
"vscode-docker.commands.containers.downloadFile": "Download",
"vscode-docker.commands.containers.inspect": "Inspect",
"vscode-docker.commands.containers.openFile": "Open",
"vscode-docker.commands.containers.prune": "Prune...",
Expand Down
104 changes: 104 additions & 0 deletions src/commands/containers/files/downloadContainerFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as path from 'path';
import * as vscode from 'vscode';
import { IActionContext, UserCancelledError } from 'vscode-azureextensionui';
import { ext } from '../../../extensionVariables';
import { localize } from '../../../localize';
import { FileTreeItem } from '../../../tree/containers/files/FileTreeItem';
import { multiSelectNodes } from '../../../utils/multiSelectNodes';

async function fileExists(file: vscode.Uri): Promise<boolean> {
try {
// NOTE: The expectation is that stat() throws when the file does not exist.
// Filed https://github.com/microsoft/vscode/issues/112107 to provide
// a better mechanism than trapping exceptions.
await vscode.workspace.fs.stat(file);

return true;
} catch {
return false;
}
}

const overwriteFile: vscode.MessageItem = {
title: localize('vscode-docker.commands.containers.files.downloadContainerFile.overwriteFile', 'Overwrite File')
};

const skipFile: vscode.MessageItem = {
title: localize('vscode-docker.commands.containers.files.downloadContainerFile.skipFile', 'Skip File')
};

const cancelDownload: vscode.MessageItem = {
title: localize('vscode-docker.commands.containers.files.downloadContainerFile.cancelDownload', 'Cancel')
};

export async function downloadContainerFile(context: IActionContext, node?: FileTreeItem, nodes?: FileTreeItem[]): Promise<void> {
nodes = await multiSelectNodes(
{ ...context, noItemFoundErrorMessage: localize('vscode-docker.commands.containers.files.downloadContainerFile.noFiles', 'No files are available to download.') },
ext.containersTree,
'containerFile',
node,
nodes
);

const localFolderUris = await vscode.window.showOpenDialog(
{
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
openLabel: localize('vscode-docker.commands.containers.files.downloadContainerFile.openLabel', 'Select'),
title: localize('vscode-docker.commands.containers.files.downloadContainerFile.openTitle', 'Select folder for download')
});

if (localFolderUris === undefined || localFolderUris.length === 0) {
throw new UserCancelledError();
}

const localFolderUri = localFolderUris[0];

const files = nodes.map(n => {
const containerFileUri = n.uri;
const fileName = path.posix.basename(containerFileUri.path);

return {
containerUri: n.uri.uri,
fileName,
localUri: vscode.Uri.joinPath(localFolderUri, fileName)
};
});

await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: localize('vscode-docker.commands.containers.files.downloadContainerFile.opening', 'Downloading File(s)...')
},
async (_, token) => {
for (const file of files) {
if (token.isCancellationRequested) {
throw new UserCancelledError();
}

const localFileExists = await fileExists(file.localUri);

if (localFileExists) {
const result = await vscode.window.showWarningMessage(
localize('vscode-docker.commands.containers.files.downloadContainerFile.existingFileWarning', 'The file \'{0}\' already exists in folder \'{1}\'.', file.fileName, localFolderUri.fsPath),
overwriteFile,
skipFile,
cancelDownload);

if (result === skipFile) {
continue;
} else if (result !== overwriteFile) {
throw new UserCancelledError();
}
}

await vscode.workspace.fs.copy(file.containerUri, file.localUri, { overwrite: true });
}
});
}
2 changes: 2 additions & 0 deletions src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { attachShellContainer } from "./containers/attachShellContainer";
import { browseContainer } from "./containers/browseContainer";
import { composeGroupDown, composeGroupLogs, composeGroupRestart } from "./containers/composeGroup";
import { configureContainersExplorer } from "./containers/configureContainersExplorer";
import { downloadContainerFile } from "./containers/files/downloadContainerFile";
import { openContainerFile } from "./containers/files/openContainerFile";
import { inspectContainer } from "./containers/inspectContainer";
import { pruneContainers } from "./containers/pruneContainers";
Expand Down Expand Up @@ -121,6 +122,7 @@ export function registerCommands(): void {

registerWorkspaceCommand('vscode-docker.containers.attachShell', attachShellContainer);
registerCommand('vscode-docker.containers.browse', browseContainer);
registerCommand('vscode-docker.containers.downloadFile', downloadContainerFile);
registerCommand('vscode-docker.containers.inspect', inspectContainer);
registerCommand('vscode-docker.containers.configureExplorer', configureContainersExplorer);
registerCommand('vscode-docker.containers.openFile', openContainerFile);
Expand Down