From f6e55987c16d91d326b257e79a6daf1b620ac6f7 Mon Sep 17 00:00:00 2001 From: "Brandon Waterloo [MSFT]" <36966225+bwateratmsft@users.noreply.github.com> Date: Tue, 6 Dec 2022 13:01:46 -0500 Subject: [PATCH] Run most commands without a shell (#3747) --- .../containers/attachShellContainer.ts | 2 +- src/commands/containers/inspectContainer.ts | 2 +- src/commands/containers/pruneContainers.ts | 2 +- src/commands/containers/restartContainer.ts | 2 +- src/commands/containers/startContainer.ts | 2 +- src/commands/containers/stopContainer.ts | 2 +- src/commands/images/inspectImage.ts | 2 +- src/commands/images/pruneImages.ts | 2 +- src/commands/images/runImage.ts | 2 +- src/commands/images/tagImage.ts | 2 +- src/commands/networks/createNetwork.ts | 2 +- src/commands/networks/inspectNetwork.ts | 2 +- src/commands/networks/pruneNetworks.ts | 2 +- src/commands/pruneSystem.ts | 8 +- src/commands/registries/logInToDockerCli.ts | 2 +- src/commands/volumes/inspectVolume.ts | 2 +- src/commands/volumes/pruneVolumes.ts | 2 +- .../DockerDebugConfigurationProvider.ts | 4 +- src/debugging/DockerServerReadyAction.ts | 4 +- src/debugging/netcore/NetCoreDebugHelper.ts | 6 +- src/debugging/python/PythonDebugHelper.ts | 4 +- src/extensionVariables.ts | 8 +- src/runtimes/ContextManager.ts | 8 +- .../DockerListNetworkRecord.ts | 158 +++++++++--------- .../parseDockerLikeEnvironmentVariables.ts | 52 +++--- .../withDockerJsonFormatArg.ts | 10 +- .../docker/commandRunners/shellStream.ts | 10 +- .../docker/commandRunners/wslStream.ts | 22 +-- src/runtimes/docker/utils/dayjs.ts | 108 ++++++------ src/runtimes/docker/utils/spawnStreamAsync.ts | 7 +- src/runtimes/files/ContainerFilesProvider.ts | 6 +- src/runtimes/runners/runWithDefaultShell.ts | 139 --------------- src/runtimes/runners/runWithDefaults.ts | 122 ++++++++++++++ src/tasks/netcore/NetCoreTaskHelper.ts | 2 +- src/tree/RefreshManager.ts | 2 +- src/tree/containers/ContainerTreeItem.ts | 4 +- src/tree/containers/ContainersTreeItem.ts | 2 +- src/tree/images/ImageTreeItem.ts | 6 +- src/tree/images/ImagesTreeItem.ts | 2 +- .../imageChecker/OutdatedImageChecker.ts | 2 +- src/tree/networks/NetworkTreeItem.ts | 6 +- src/tree/networks/NetworksTreeItem.ts | 2 +- src/tree/volumes/VolumeTreeItem.ts | 6 +- src/tree/volumes/VolumesTreeItem.ts | 2 +- src/utils/RuntimeInstallStatusProvider.ts | 2 +- src/utils/osUtils.ts | 2 +- 46 files changed, 364 insertions(+), 384 deletions(-) delete mode 100644 src/runtimes/runners/runWithDefaultShell.ts create mode 100644 src/runtimes/runners/runWithDefaults.ts diff --git a/src/commands/containers/attachShellContainer.ts b/src/commands/containers/attachShellContainer.ts index 9d1fc1b4..cf89195a 100644 --- a/src/commands/containers/attachShellContainer.ts +++ b/src/commands/containers/attachShellContainer.ts @@ -33,7 +33,7 @@ export async function attachShellContainer(context: IActionContext, node?: Conta // If so use it, otherwise use sh try { // If this succeeds, bash is present (exit code 0) - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => // Since we're not interested in the output, just the exit code, we can pretend this is a `VoidCommandResponse` client.execContainer({ container: node.containerId, interactive: true, command: ['sh', '-c', 'which bash'] }) as Promise ); diff --git a/src/commands/containers/inspectContainer.ts b/src/commands/containers/inspectContainer.ts index f9aedb31..8029848f 100644 --- a/src/commands/containers/inspectContainer.ts +++ b/src/commands/containers/inspectContainer.ts @@ -17,7 +17,7 @@ export async function inspectContainer(context: IActionContext, node?: Container }); } - const inspectInfo = await ext.runWithDefaultShell(client => + const inspectInfo = await ext.runWithDefaults(client => client.inspectContainers({ containers: [node.containerId] }) ); await openReadOnlyJson(node, JSON.parse(inspectInfo[0].raw)); diff --git a/src/commands/containers/pruneContainers.ts b/src/commands/containers/pruneContainers.ts index 9175d793..61b6553e 100644 --- a/src/commands/containers/pruneContainers.ts +++ b/src/commands/containers/pruneContainers.ts @@ -17,7 +17,7 @@ export async function pruneContainers(context: IActionContext): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.pruning', 'Pruning containers...') }, async () => { - const result = await ext.runWithDefaultShell(client => + const result = await ext.runWithDefaults(client => client.pruneContainers({}) ); diff --git a/src/commands/containers/restartContainer.ts b/src/commands/containers/restartContainer.ts index b88472b5..810b2cb9 100644 --- a/src/commands/containers/restartContainer.ts +++ b/src/commands/containers/restartContainer.ts @@ -20,7 +20,7 @@ export async function restartContainer(context: IActionContext, node?: Container ); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.restart.restarting', 'Restarting Container(s)...') }, async () => { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.restartContainers({ container: nodes.map(n => n.containerId) }) ); }); diff --git a/src/commands/containers/startContainer.ts b/src/commands/containers/startContainer.ts index deabeafe..210d2d77 100644 --- a/src/commands/containers/startContainer.ts +++ b/src/commands/containers/startContainer.ts @@ -20,7 +20,7 @@ export async function startContainer(context: IActionContext, node?: ContainerTr ); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.start.starting', 'Starting Container(s)...') }, async () => { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.startContainers({ container: nodes.map(n => n.containerId) }) ); }); diff --git a/src/commands/containers/stopContainer.ts b/src/commands/containers/stopContainer.ts index edc083a2..a91abdd8 100644 --- a/src/commands/containers/stopContainer.ts +++ b/src/commands/containers/stopContainer.ts @@ -20,7 +20,7 @@ export async function stopContainer(context: IActionContext, node?: ContainerTre ); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.containers.stop.stopping', 'Stopping Container(s)...') }, async () => { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.stopContainers({ container: nodes.map(n => n.containerId) }) ); }); diff --git a/src/commands/images/inspectImage.ts b/src/commands/images/inspectImage.ts index d0ee64dd..307ba02d 100644 --- a/src/commands/images/inspectImage.ts +++ b/src/commands/images/inspectImage.ts @@ -17,7 +17,7 @@ export async function inspectImage(context: IActionContext, node?: ImageTreeItem }); } - const inspectResult = await ext.runWithDefaultShell(client => + const inspectResult = await ext.runWithDefaults(client => client.inspectImages({ imageRefs: [node.imageId] }) ); await openReadOnlyJson(node, JSON.parse(inspectResult[0].raw)); diff --git a/src/commands/images/pruneImages.ts b/src/commands/images/pruneImages.ts index ab8c8080..49de5896 100644 --- a/src/commands/images/pruneImages.ts +++ b/src/commands/images/pruneImages.ts @@ -17,7 +17,7 @@ export async function pruneImages(context: IActionContext): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.images.pruning', 'Pruning images...') }, async () => { - const result = await ext.runWithDefaultShell(client => + const result = await ext.runWithDefaults(client => client.pruneImages({}) ); diff --git a/src/commands/images/runImage.ts b/src/commands/images/runImage.ts index 253309d2..038d8641 100644 --- a/src/commands/images/runImage.ts +++ b/src/commands/images/runImage.ts @@ -27,7 +27,7 @@ async function runImageCore(context: IActionContext, node: ImageTreeItem | undef }); } - const inspectResult = await ext.runWithDefaultShell(client => + const inspectResult = await ext.runWithDefaults(client => client.inspectImages({ imageRefs: [node.imageId] }) ); diff --git a/src/commands/images/tagImage.ts b/src/commands/images/tagImage.ts index cdb69f7c..f8c4cba3 100644 --- a/src/commands/images/tagImage.ts +++ b/src/commands/images/tagImage.ts @@ -23,7 +23,7 @@ export async function tagImage(context: IActionContext, node?: ImageTreeItem, re const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, registry?.baseImagePath); addImageTaggingTelemetry(context, newTaggedName, '.after'); - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.tagImage({ fromImageRef: node.imageId, toImageRef: newTaggedName }) ); diff --git a/src/commands/networks/createNetwork.ts b/src/commands/networks/createNetwork.ts index 5ecb4b01..3715cf1a 100644 --- a/src/commands/networks/createNetwork.ts +++ b/src/commands/networks/createNetwork.ts @@ -36,7 +36,7 @@ export async function createNetwork(context: IActionContext): Promise { } ); - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.createNetwork({ name: name, driver: driverSelection.label }) ); } diff --git a/src/commands/networks/inspectNetwork.ts b/src/commands/networks/inspectNetwork.ts index 37ee1cf9..103aeeef 100644 --- a/src/commands/networks/inspectNetwork.ts +++ b/src/commands/networks/inspectNetwork.ts @@ -17,7 +17,7 @@ export async function inspectNetwork(context: IActionContext, node?: NetworkTree }); } - const inspectResult = await ext.runWithDefaultShell(client => + const inspectResult = await ext.runWithDefaults(client => client.inspectNetworks({ networks: [node.networkId] }) ); await openReadOnlyJson(node, JSON.parse(inspectResult[0].raw)); diff --git a/src/commands/networks/pruneNetworks.ts b/src/commands/networks/pruneNetworks.ts index 9a2e9e00..c2f66c43 100644 --- a/src/commands/networks/pruneNetworks.ts +++ b/src/commands/networks/pruneNetworks.ts @@ -16,7 +16,7 @@ export async function pruneNetworks(context: IActionContext): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.networks.pruning', 'Pruning networks...') }, async () => { - const result = await ext.runWithDefaultShell(client => + const result = await ext.runWithDefaults(client => client.pruneNetworks({}) ); diff --git a/src/commands/pruneSystem.ts b/src/commands/pruneSystem.ts index 1a064d28..91668981 100644 --- a/src/commands/pruneSystem.ts +++ b/src/commands/pruneSystem.ts @@ -17,16 +17,16 @@ export async function pruneSystem(context: IActionContext): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.pruneSystem.pruning', 'Pruning system...') }, async () => { - const containersResult = await ext.runWithDefaultShell(client => + const containersResult = await ext.runWithDefaults(client => client.pruneContainers({}) ); - const imagesResult = await ext.runWithDefaultShell(client => + const imagesResult = await ext.runWithDefaults(client => client.pruneImages({}) ); - const networksResult = await ext.runWithDefaultShell(client => + const networksResult = await ext.runWithDefaults(client => client.pruneNetworks({}) ); - const volumesResult = await ext.runWithDefaultShell(client => + const volumesResult = await ext.runWithDefaults(client => client.pruneVolumes({}) ); diff --git a/src/commands/registries/logInToDockerCli.ts b/src/commands/registries/logInToDockerCli.ts index 69bbf36c..e836b42c 100644 --- a/src/commands/registries/logInToDockerCli.ts +++ b/src/commands/registries/logInToDockerCli.ts @@ -39,7 +39,7 @@ export async function logInToDockerCli(context: IActionContext, node?: RegistryT await vscode.window.withProgress(progressOptions, async () => { try { - await ext.runWithDefaultShell( + await ext.runWithDefaults( client => client.login({ username: username, passwordStdIn: true, diff --git a/src/commands/volumes/inspectVolume.ts b/src/commands/volumes/inspectVolume.ts index 8aa8c5c4..694a9541 100644 --- a/src/commands/volumes/inspectVolume.ts +++ b/src/commands/volumes/inspectVolume.ts @@ -14,7 +14,7 @@ export async function inspectVolume(context: IActionContext, node?: VolumeTreeIt node = await ext.volumesTree.showTreeItemPicker(VolumeTreeItem.contextValue, { ...context, noItemFoundErrorMessage: localize('vscode-docker.commands.volumes.inspect.noVolumes', 'No volumes are available to inspect') }); } - const inspectResult = await ext.runWithDefaultShell(client => + const inspectResult = await ext.runWithDefaults(client => client.inspectVolumes({ volumes: [node.volumeName] }) ); await openReadOnlyJson(node, JSON.parse(inspectResult[0].raw)); diff --git a/src/commands/volumes/pruneVolumes.ts b/src/commands/volumes/pruneVolumes.ts index 6a0513a3..e09000ab 100644 --- a/src/commands/volumes/pruneVolumes.ts +++ b/src/commands/volumes/pruneVolumes.ts @@ -17,7 +17,7 @@ export async function pruneVolumes(context: IActionContext): Promise { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: localize('vscode-docker.commands.volumes.pruning', 'Pruning volumes...') }, async () => { - const result = await ext.runWithDefaultShell(client => + const result = await ext.runWithDefaults(client => client.pruneVolumes({}) ); diff --git a/src/debugging/DockerDebugConfigurationProvider.ts b/src/debugging/DockerDebugConfigurationProvider.ts index c79556c4..c46acc45 100644 --- a/src/debugging/DockerDebugConfigurationProvider.ts +++ b/src/debugging/DockerDebugConfigurationProvider.ts @@ -141,7 +141,7 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi configuration?.dockerOptions?.containerName && // containerName must be specified !(configuration?.subProcessId)) { // Must not have subProcessId, i.e. not a subprocess debug session (which is how Python does hot reload sessions) try { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeContainers({ containers: [configuration.dockerOptions.containerName], force: true }) ); } catch { @@ -153,7 +153,7 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi private async outputPortsAtDebuggingIfNeeded(context: IActionContext, configuration: ResolvedDebugConfiguration): Promise { if (configuration?.dockerOptions?.containerName) { try { - const inspectInfo = (await ext.runWithDefaultShell(client => + const inspectInfo = (await ext.runWithDefaults(client => client.inspectContainers({ containers: [configuration.dockerOptions.containerName] }) ))?.[0]; const portMappings: string[] = []; diff --git a/src/debugging/DockerServerReadyAction.ts b/src/debugging/DockerServerReadyAction.ts index d1eb0d49..5b893603 100644 --- a/src/debugging/DockerServerReadyAction.ts +++ b/src/debugging/DockerServerReadyAction.ts @@ -134,7 +134,7 @@ class ServerReadyDetector implements DockerServerReadyDetector { } private async getHostPortForContainerPort(containerName: string, containerPort: number): Promise { - const containerInspectInfo = (await ext.runWithDefaultShell(client => + const containerInspectInfo = (await ext.runWithDefaults(client => client.inspectContainers({ containers: [containerName] }) ))?.[0]; const hostPort = containerInspectInfo?.ports.find(p => p.containerPort === containerPort)?.hostPort; @@ -211,7 +211,7 @@ class DockerLogsTracker extends vscode.Disposable { private async listen(): Promise { try { - const generator = ext.streamWithDefaultShell( + const generator = ext.streamWithDefaults( client => client.logsForContainer({ container: this.containerName, follow: true }), { cancellationToken: this.cts.token, diff --git a/src/debugging/netcore/NetCoreDebugHelper.ts b/src/debugging/netcore/NetCoreDebugHelper.ts index 4b8cb522..ae487803 100644 --- a/src/debugging/netcore/NetCoreDebugHelper.ts +++ b/src/debugging/netcore/NetCoreDebugHelper.ts @@ -268,7 +268,7 @@ export class NetCoreDebugHelper implements DebugHelper { private async copyDebuggerToContainer(context: IActionContext, containerName: string, containerDebuggerDirectory: string, containerOS: ContainerOS): Promise { if (containerOS === 'windows') { - const inspectInfo = (await ext.runWithDefaultShell(client => + const inspectInfo = (await ext.runWithDefaults(client => client.inspectContainers({ containers: [containerName] }) ))?.[0]; const containerInfo = inspectInfo ? JSON.parse(inspectInfo.raw) : undefined; @@ -295,7 +295,7 @@ export class NetCoreDebugHelper implements DebugHelper { location: ProgressLocation.Notification, title: localize('vscode-docker.debug.netcore.copyDebugger', 'Copying the .NET Core debugger to the container ({0} --> {1})...', vsDbgInstallBasePath, containerDebuggerDirectory), }, async () => { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.writeFile({ container: containerName, inputFile: vsDbgInstallBasePath, @@ -323,7 +323,7 @@ export class NetCoreDebugHelper implements DebugHelper { } try { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => // Since we're not interested in the output, just the exit code, we can pretend this is a `VoidCommandResponse` client.execContainer({ container: containerName, diff --git a/src/debugging/python/PythonDebugHelper.ts b/src/debugging/python/PythonDebugHelper.ts index a94080f4..430f2f00 100644 --- a/src/debugging/python/PythonDebugHelper.ts +++ b/src/debugging/python/PythonDebugHelper.ts @@ -144,7 +144,7 @@ export class PythonDebugHelper implements DebugHelper { } // For Docker Desktop on WSL or Linux, we also use 'localhost' - const dockerInfo = await ext.runWithDefaultShell(client => + const dockerInfo = await ext.runWithDefaults(client => client.info({}) ); @@ -154,7 +154,7 @@ export class PythonDebugHelper implements DebugHelper { // For other Docker setups on WSL or Linux, 'host.docker.internal' doesn't work, so we ask debugpy to listen // on the bridge network's ip address (predefined network). - const networkInspection = (await ext.runWithDefaultShell(client => + const networkInspection = (await ext.runWithDefaults(client => client.inspectNetworks({ networks: ['bridge'] }) ))?.[0]; diff --git a/src/extensionVariables.ts b/src/extensionVariables.ts index ab324bae..0a3df692 100644 --- a/src/extensionVariables.ts +++ b/src/extensionVariables.ts @@ -14,7 +14,7 @@ import { NetworksTreeItem } from './tree/networks/NetworksTreeItem'; import { RegistriesTreeItem } from './tree/registries/RegistriesTreeItem'; import { VolumesTreeItem } from './tree/volumes/VolumesTreeItem'; import { OrchestratorRuntimeManager } from './runtimes/OrchestratorRuntimeManager'; -import { runOrchestratorWithDefaultShellInternal, runWithDefaultShellInternal, streamOrchestratorWithDefaultShellInternal, streamWithDefaultShellInternal } from './runtimes/runners/runWithDefaultShell'; +import { runWithDefaults as runWithDefaultsImpl, streamWithDefaults as streamWithDefaultsImpl } from './runtimes/runners/runWithDefaults'; /** * Namespace for common variables used throughout the extension. They must be initialized in the activate() method of extension.ts @@ -59,8 +59,6 @@ export namespace ext { // Container runtime related items export let runtimeManager: ContainerRuntimeManager; export let orchestratorManager: OrchestratorRuntimeManager; - export const runWithDefaultShell = runWithDefaultShellInternal; - export const streamWithDefaultShell = streamWithDefaultShellInternal; - export const runOrchestratorWithDefaultShell = runOrchestratorWithDefaultShellInternal; - export const streamOrchestratorWithDefaultShell = streamOrchestratorWithDefaultShellInternal; + export const runWithDefaults = runWithDefaultsImpl; + export const streamWithDefaults = streamWithDefaultsImpl; } diff --git a/src/runtimes/ContextManager.ts b/src/runtimes/ContextManager.ts index 07bece3d..1d270e66 100644 --- a/src/runtimes/ContextManager.ts +++ b/src/runtimes/ContextManager.ts @@ -39,7 +39,7 @@ export class ContextManager implements IContextManager, vscode.Disposable { } public async getContexts(): Promise { - const allContexts = await ext.runWithDefaultShell(client => + const allContexts = await ext.runWithDefaults(client => client.listContexts({}) ) || []; const currentContext: ListContextItem | undefined = this.tryGetCurrentContext(allContexts); @@ -58,20 +58,20 @@ export class ContextManager implements IContextManager, vscode.Disposable { } public async useContext(name: string): Promise { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.useContext({ context: name }) ); await this.getCurrentContext(); // Reestablish the current context, to cause the change emitter to fire indirectly if the context has actually changed } public async removeContext(name: string): Promise { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeContexts({ contexts: [name] }) ); } public async inspectContext(name: string): Promise { - const result = await ext.runWithDefaultShell(client => + const result = await ext.runWithDefaults(client => client.inspectContexts({ contexts: [name] }) ); return result?.[0]; diff --git a/src/runtimes/docker/clients/DockerClientBase/DockerListNetworkRecord.ts b/src/runtimes/docker/clients/DockerClientBase/DockerListNetworkRecord.ts index 5500581d..de1d9563 100644 --- a/src/runtimes/docker/clients/DockerClientBase/DockerListNetworkRecord.ts +++ b/src/runtimes/docker/clients/DockerClientBase/DockerListNetworkRecord.ts @@ -1,79 +1,79 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ListNetworkItem } from '../../contracts/ContainerClient'; -import { dayjs } from '../../utils/dayjs'; -import { parseDockerLikeLabels } from './parseDockerLikeLabels'; - -export type DockerListNetworkRecord = { - ID: string; - Name: string; - Driver: string; - Labels: string; - Scope: string; - IPv6: string; - CreatedAt: string; - Internal: string; -}; - -export function isDockerListNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerListNetworkRecord { - const network = maybeNetwork as DockerListNetworkRecord; - - if (!network || typeof network !== 'object') { - return false; - } - - if (typeof network.ID !== 'string') { - return false; - } - - if (typeof network.Name !== 'string') { - return false; - } - - if (typeof network.Driver !== 'string') { - return false; - } - - if (typeof network.Labels !== 'string') { - return false; - } - - if (typeof network.Scope !== 'string') { - return false; - } - - if (typeof network.IPv6 !== 'string') { - return false; - } - - if (typeof network.CreatedAt !== 'string') { - return false; - } - - if (typeof network.Internal !== 'string') { - return false; - } - - return true; -} - -export function normalizeDockerListNetworkRecord(network: DockerListNetworkRecord): ListNetworkItem { - // Parse the labels assigned to the networks and normalize to key value pairs - const labels = parseDockerLikeLabels(network.Labels); - - const createdAt = dayjs.utc(network.CreatedAt).toDate(); - - return { - id: network.ID, - name: network.Name, - driver: network.Driver, - labels, - scope: network.Scope, - ipv6: network.IPv6.toLowerCase() === 'true', - internal: network.Internal.toLowerCase() === 'true', - createdAt, - }; -} +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ListNetworkItem } from '../../contracts/ContainerClient'; +import { dayjs } from '../../utils/dayjs'; +import { parseDockerLikeLabels } from './parseDockerLikeLabels'; + +export type DockerListNetworkRecord = { + ID: string; + Name: string; + Driver: string; + Labels: string; + Scope: string; + IPv6: string; + CreatedAt: string; + Internal: string; +}; + +export function isDockerListNetworkRecord(maybeNetwork: unknown): maybeNetwork is DockerListNetworkRecord { + const network = maybeNetwork as DockerListNetworkRecord; + + if (!network || typeof network !== 'object') { + return false; + } + + if (typeof network.ID !== 'string') { + return false; + } + + if (typeof network.Name !== 'string') { + return false; + } + + if (typeof network.Driver !== 'string') { + return false; + } + + if (typeof network.Labels !== 'string') { + return false; + } + + if (typeof network.Scope !== 'string') { + return false; + } + + if (typeof network.IPv6 !== 'string') { + return false; + } + + if (typeof network.CreatedAt !== 'string') { + return false; + } + + if (typeof network.Internal !== 'string') { + return false; + } + + return true; +} + +export function normalizeDockerListNetworkRecord(network: DockerListNetworkRecord): ListNetworkItem { + // Parse the labels assigned to the networks and normalize to key value pairs + const labels = parseDockerLikeLabels(network.Labels); + + const createdAt = dayjs.utc(network.CreatedAt).toDate(); + + return { + id: network.ID, + name: network.Name, + driver: network.Driver, + labels, + scope: network.Scope, + ipv6: network.IPv6.toLowerCase() === 'true', + internal: network.Internal.toLowerCase() === 'true', + createdAt, + }; +} diff --git a/src/runtimes/docker/clients/DockerClientBase/parseDockerLikeEnvironmentVariables.ts b/src/runtimes/docker/clients/DockerClientBase/parseDockerLikeEnvironmentVariables.ts index 7123e900..7eebdb83 100644 --- a/src/runtimes/docker/clients/DockerClientBase/parseDockerLikeEnvironmentVariables.ts +++ b/src/runtimes/docker/clients/DockerClientBase/parseDockerLikeEnvironmentVariables.ts @@ -1,26 +1,26 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/** - * Parse the standard Docker environment variable format into a key value record object - * @param environmentVariables A Docker like list of key=value environment variables - * @returns An object of key value pairs for the environment variables - */ -export function parseDockerLikeEnvironmentVariables(environmentVariables: Array): Record { - return environmentVariables.reduce>((evs, ev) => { - const index = ev.indexOf('='); - if (index > -1) { - const name = ev.slice(0, index); - const value = ev.slice(index + 1); - - return { - ...evs, - [name]: value, - }; - } - - return evs; - }, {}); -} +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Parse the standard Docker environment variable format into a key value record object + * @param environmentVariables A Docker like list of key=value environment variables + * @returns An object of key value pairs for the environment variables + */ +export function parseDockerLikeEnvironmentVariables(environmentVariables: Array): Record { + return environmentVariables.reduce>((evs, ev) => { + const index = ev.indexOf('='); + if (index > -1) { + const name = ev.slice(0, index); + const value = ev.slice(index + 1); + + return { + ...evs, + [name]: value, + }; + } + + return evs; + }, {}); +} diff --git a/src/runtimes/docker/clients/DockerClientBase/withDockerJsonFormatArg.ts b/src/runtimes/docker/clients/DockerClientBase/withDockerJsonFormatArg.ts index 0e4c5629..e6cf78f1 100644 --- a/src/runtimes/docker/clients/DockerClientBase/withDockerJsonFormatArg.ts +++ b/src/runtimes/docker/clients/DockerClientBase/withDockerJsonFormatArg.ts @@ -3,6 +3,12 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { withNamedArg } from '../../utils/commandLineBuilder'; +import { composeArgs, withArg, withVerbatimArg } from '../../utils/commandLineBuilder'; -export const withDockerJsonFormatArg = withNamedArg('--format', '{{json .}}'); +// Because Docker's wrapper script would split up `{{json .}}` into two arguments, we need to +// pre-quote it to prevent that, for cases where we're executing without a shell. +// Making it a verbatim argument also prevents it from being requoted later. +export const withDockerJsonFormatArg = composeArgs( + withArg('--format'), + withVerbatimArg('"{{json .}}"'), +); diff --git a/src/runtimes/docker/commandRunners/shellStream.ts b/src/runtimes/docker/commandRunners/shellStream.ts index 6ca66d62..032ab8df 100644 --- a/src/runtimes/docker/commandRunners/shellStream.ts +++ b/src/runtimes/docker/commandRunners/shellStream.ts @@ -18,8 +18,8 @@ import { import { CancellationTokenLike } from '../typings/CancellationTokenLike'; import { AccumulatorStream } from '../utils/AccumulatorStream'; import { CancellationError } from '../utils/CancellationError'; +import { CommandLineArgs } from '../utils/commandLineBuilder'; import { - Shell, spawnStreamAsync, StreamSpawnOptions, } from '../utils/spawnStreamAsync'; @@ -94,12 +94,8 @@ export class ShellStreamCommandRunnerFactory implements ICommandRunnerFactory { - protected override getCommandAndArgs( - commandResponse: CommandResponseBase, - ): { - command: string; - args: string[]; - } { + protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } { const command = this.options.wslPath ?? 'wsl.exe'; - const args = [ - ...(this.options.distro ? ['-d', this.options.distro] : []), - '--', - commandResponse.command, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ...Shell.getShellOrDefault(this.options.shellProvider).quote(commandResponse.args), - ]; + const args = composeArgs( + withNamedArg('-d', this.options.distro), + withArg('--'), + withArg(commandResponse.command), + withArg(...commandResponse.args), + )(); return { command, args }; } diff --git a/src/runtimes/docker/utils/dayjs.ts b/src/runtimes/docker/utils/dayjs.ts index d32b312f..68cb7d7f 100644 --- a/src/runtimes/docker/utils/dayjs.ts +++ b/src/runtimes/docker/utils/dayjs.ts @@ -1,54 +1,54 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as dayjsinner from 'dayjs'; -import * as customParseFormat from 'dayjs/plugin/customParseFormat'; -import * as utc from 'dayjs/plugin/utc'; - -dayjsinner.extend(customParseFormat); -dayjsinner.extend(utc); - -const defaultFormats = ['YYYY-MM-DD HH:mm:ss ZZ']; - -/** - * Wrap the dayjs methods to apply a default Docker friendly format to all parsing - */ -export const dayjs = new Proxy(dayjsinner, { - apply(target, thisArg, argArray: Parameters) { - const formats = [...defaultFormats]; // formats should always include default Docker date format - if (argArray.length > 1) { - if (typeof argArray[1] === 'string' || Array.isArray(argArray[1])) { - argArray[1] = formats.concat(argArray[1]); - } - } else if (argArray.length === 1) { - argArray.push(formats); - } - - return target.apply(thisArg, argArray); - }, - get(target, prop, receiver) { - const value = Reflect.get(target, prop, receiver); - if (typeof value === 'function') { - if (prop === 'utc') { - return function (this: typeof dayjsinner, ...args: Array) { - const formats = [...defaultFormats]; // formats should always include default Docker date format - if (args.length > 1) { - if (typeof args[1] === 'string' || Array.isArray(args[1])) { - args[1] = formats.concat(args[1]); - } - } else if (args.length === 1) { - args.push(formats); - } - - return value.apply(this === receiver ? target : this, args); - }; - } - - return value.bind(this === receiver ? target : this); - } else { - return value; - } - }, -}); +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as dayjsinner from 'dayjs'; +import * as customParseFormat from 'dayjs/plugin/customParseFormat'; +import * as utc from 'dayjs/plugin/utc'; + +dayjsinner.extend(customParseFormat); +dayjsinner.extend(utc); + +const defaultFormats = ['YYYY-MM-DD HH:mm:ss ZZ']; + +/** + * Wrap the dayjs methods to apply a default Docker friendly format to all parsing + */ +export const dayjs = new Proxy(dayjsinner, { + apply(target, thisArg, argArray: Parameters) { + const formats = [...defaultFormats]; // formats should always include default Docker date format + if (argArray.length > 1) { + if (typeof argArray[1] === 'string' || Array.isArray(argArray[1])) { + argArray[1] = formats.concat(argArray[1]); + } + } else if (argArray.length === 1) { + argArray.push(formats); + } + + return target.apply(thisArg, argArray); + }, + get(target, prop, receiver) { + const value = Reflect.get(target, prop, receiver); + if (typeof value === 'function') { + if (prop === 'utc') { + return function (this: typeof dayjsinner, ...args: Array) { + const formats = [...defaultFormats]; // formats should always include default Docker date format + if (args.length > 1) { + if (typeof args[1] === 'string' || Array.isArray(args[1])) { + args[1] = formats.concat(args[1]); + } + } else if (args.length === 1) { + args.push(formats); + } + + return value.apply(this === receiver ? target : this, args); + }; + } + + return value.bind(this === receiver ? target : this); + } else { + return value; + } + }, +}); diff --git a/src/runtimes/docker/utils/spawnStreamAsync.ts b/src/runtimes/docker/utils/spawnStreamAsync.ts index c1ff248a..9d82c44a 100644 --- a/src/runtimes/docker/utils/spawnStreamAsync.ts +++ b/src/runtimes/docker/utils/spawnStreamAsync.ts @@ -141,7 +141,7 @@ export type StreamSpawnOptions = SpawnOptions & { export async function spawnStreamAsync( command: string, - args: Array, + args: CommandLineArgs, options: StreamSpawnOptions, ): Promise { const cancellationToken = options.cancellationToken || CancellationTokenLike.None; @@ -149,6 +149,9 @@ export async function spawnStreamAsync( // *nix const shell = options.shellProvider?.getShellOrDefault(options.shell) ?? options.shell; + // If there is a shell provider, apply its quoting, otherwise just flatten arguments into strings + const normalizedArgs: string[] = options.shellProvider?.quote(args) ?? args.map(arg => typeof arg === 'string' ? arg : arg.value); + if (cancellationToken.isCancellationRequested) { throw new CancellationError('Command cancelled', cancellationToken); } @@ -159,7 +162,7 @@ export async function spawnStreamAsync( const childProcess = spawn( command, - args, + normalizedArgs, { ...options, shell, diff --git a/src/runtimes/files/ContainerFilesProvider.ts b/src/runtimes/files/ContainerFilesProvider.ts index 259c5dce..b713fb9f 100644 --- a/src/runtimes/files/ContainerFilesProvider.ts +++ b/src/runtimes/files/ContainerFilesProvider.ts @@ -54,7 +54,7 @@ export class ContainerFilesProvider extends vscode.Disposable implements vscode. const dockerUri = DockerUri.parse(uri); const containerOS = dockerUri.options?.containerOS || await getDockerOSType(); - const items: ListFilesItem[] = await ext.runWithDefaultShell(client => + const items: ListFilesItem[] = await ext.runWithDefaults(client => client.listFiles({ container: dockerUri.containerId, path: containerOS === 'windows' ? dockerUri.windowsPath : dockerUri.path, @@ -81,7 +81,7 @@ export class ContainerFilesProvider extends vscode.Disposable implements vscode. const accumulator = new AccumulatorStream(); const targetStream = containerOS === 'windows' ? accumulator : tarUnpackStream(accumulator); - const generator = ext.streamWithDefaultShell( + const generator = ext.streamWithDefaults( client => client.readFile({ container: dockerUri.containerId, path: containerOS === 'windows' ? dockerUri.windowsPath : dockerUri.path, @@ -108,7 +108,7 @@ export class ContainerFilesProvider extends vscode.Disposable implements vscode. path.win32.dirname(dockerUri.windowsPath) : path.posix.dirname(dockerUri.path); - await ext.runWithDefaultShell( + await ext.runWithDefaults( client => client.writeFile({ container: dockerUri.containerId, path: destDirectory, diff --git a/src/runtimes/runners/runWithDefaultShell.ts b/src/runtimes/runners/runWithDefaultShell.ts deleted file mode 100644 index 87493ea8..00000000 --- a/src/runtimes/runners/runWithDefaultShell.ts +++ /dev/null @@ -1,139 +0,0 @@ -/*!-------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { AccumulatorStream, ClientIdentity, GeneratorCommandResponse, IContainerOrchestratorClient, IContainersClient, isChildProcessError, Like, normalizeCommandResponseLike, PromiseCommandResponse, Shell, ShellStreamCommandRunnerFactory, ShellStreamCommandRunnerOptions, VoidCommandResponse } from '../docker'; -import { ext } from '../../extensionVariables'; -import { RuntimeManager } from '../RuntimeManager'; -import { withDockerEnvSettings } from '../../utils/withDockerEnvSettings'; - -type ClientCallback = (client: TClient) => Like>; -type VoidClientCallback = (client: TClient) => Like; -type StreamingClientCallback = (client: TClient) => Like>; - -// 'env', 'shellProvider', 'stdErrPipe', and 'strict' are set by this function and thus should not be included as arguments to the additional options -type DefaultEnvShellStreamCommandRunnerOptions = Omit; - -export async function runWithDefaultShellInternal(callback: ClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise; -export async function runWithDefaultShellInternal(callback: VoidClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise; -export async function runWithDefaultShellInternal(callback: ClientCallback | VoidClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise { - return await runWithDefaultShell( - callback, - ext.runtimeManager, - additionalOptions - ); -} - -export function streamWithDefaultShellInternal(callback: StreamingClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): AsyncGenerator { - return streamWithDefaultShell( - callback, - ext.runtimeManager, - additionalOptions - ); -} - -export async function runOrchestratorWithDefaultShellInternal(callback: ClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise; -export async function runOrchestratorWithDefaultShellInternal(callback: VoidClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise; -export async function runOrchestratorWithDefaultShellInternal(callback: ClientCallback | VoidClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise { - return await runWithDefaultShell( - callback, - ext.orchestratorManager, - additionalOptions - ); -} - -export function streamOrchestratorWithDefaultShellInternal(callback: StreamingClientCallback, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): AsyncGenerator { - return streamWithDefaultShell( - callback, - ext.orchestratorManager, - additionalOptions - ); -} - -async function runWithDefaultShell( - callback: ClientCallback | VoidClientCallback, - runtimeManager: RuntimeManager, - additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions -): Promise { - // Get a `DefaultEnvShellStreamCommandRunnerFactory` - const factory = new DefaultEnvShellStreamCommandRunnerFactory(additionalOptions); - - // Get the active client - const client: TClient = await runtimeManager.getClient(); - - try { - // Flatten the callback - const response = await normalizeCommandResponseLike(callback(client)); - - if (response.parse) { - return await factory.getCommandRunner()(response as PromiseCommandResponse); - } else { - await factory.getCommandRunner()(response as VoidCommandResponse); - } - } catch (err) { - if (isChildProcessError(err)) { - // If this is a child process error, alter the message to be the stderr output, if it isn't falsy - const stdErr = await factory.errAccumulator.getString(); - err.message = stdErr || err.message; - } - - throw err; - } finally { - factory.dispose(); - } -} - -async function* streamWithDefaultShell( - callback: StreamingClientCallback, - runtimeManager: RuntimeManager, - additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions -): AsyncGenerator { - // Get a `DefaultEnvShellStreamCommandRunnerFactory` - const factory = new DefaultEnvShellStreamCommandRunnerFactory(additionalOptions); - - // Get the active client - const client: TClient = await runtimeManager.getClient(); - - try { - const runner = factory.getStreamingCommandRunner(); - const generator = runner(callback(client)); - - for await (const element of generator) { - yield element; - } - } catch (err) { - if (isChildProcessError(err)) { - // If this is a child process error, alter the message to be the stderr output, if it isn't falsy - const stdErr = await factory.errAccumulator.getString(); - err.message = stdErr || err.message; - } - - throw err; - } finally { - factory.dispose(); - } -} - -class DefaultEnvShellStreamCommandRunnerFactory extends ShellStreamCommandRunnerFactory implements vscode.Disposable { - public readonly errAccumulator: AccumulatorStream; - - public constructor(options: TOptions) { - const errAccumulator = new AccumulatorStream(); - - super({ - ...options, - strict: true, - stdErrPipe: errAccumulator, - shellProvider: Shell.getShellOrDefault(), - env: withDockerEnvSettings(process.env), - }); - - this.errAccumulator = errAccumulator; - } - - public dispose(): void { - this.errAccumulator.destroy(); - } -} diff --git a/src/runtimes/runners/runWithDefaults.ts b/src/runtimes/runners/runWithDefaults.ts new file mode 100644 index 00000000..db0e1e4d --- /dev/null +++ b/src/runtimes/runners/runWithDefaults.ts @@ -0,0 +1,122 @@ +/*!-------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { AccumulatorStream, ClientIdentity, GeneratorCommandResponse, IContainersClient, isChildProcessError, Like, normalizeCommandResponseLike, PromiseCommandResponse, ShellStreamCommandRunnerFactory, ShellStreamCommandRunnerOptions, VoidCommandResponse } from '../docker'; +import { ext } from '../../extensionVariables'; +import { RuntimeManager } from '../RuntimeManager'; +import { withDockerEnvSettings } from '../../utils/withDockerEnvSettings'; + +type ClientCallback = (client: TClient) => Like>; +type VoidClientCallback = (client: TClient) => Like; +type StreamingClientCallback = (client: TClient) => Like>; + +// 'env', 'shell', 'shellProvider', 'stdErrPipe', and 'strict' are set by this function and thus should not be included as arguments to the additional options +type DefaultEnvStreamCommandRunnerOptions = Omit; + +export async function runWithDefaults(callback: ClientCallback, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise; +export async function runWithDefaults(callback: VoidClientCallback, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise; +export async function runWithDefaults(callback: ClientCallback | VoidClientCallback, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise { + return await runWithDefaultsInternal( + callback, + ext.runtimeManager, + additionalOptions + ); +} + +export function streamWithDefaults(callback: StreamingClientCallback, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): AsyncGenerator { + return streamWithDefaultsInternal( + callback, + ext.runtimeManager, + additionalOptions + ); +} + +async function runWithDefaultsInternal( + callback: ClientCallback | VoidClientCallback, + runtimeManager: RuntimeManager, + additionalOptions?: DefaultEnvStreamCommandRunnerOptions +): Promise { + // Get a `DefaultEnvStreamCommandRunnerFactory` + const factory = new DefaultEnvStreamCommandRunnerFactory(additionalOptions); + + // Get the active client + const client: TClient = await runtimeManager.getClient(); + + try { + // Flatten the callback + const response = await normalizeCommandResponseLike(callback(client)); + + if (response.parse) { + return await factory.getCommandRunner()(response as PromiseCommandResponse); + } else { + await factory.getCommandRunner()(response as VoidCommandResponse); + } + } catch (err) { + if (isChildProcessError(err)) { + // If this is a child process error, alter the message to be the stderr output, if it isn't falsy + const stdErr = await factory.errAccumulator.getString(); + err.message = stdErr || err.message; + } + + throw err; + } finally { + factory.dispose(); + } +} + +async function* streamWithDefaultsInternal( + callback: StreamingClientCallback, + runtimeManager: RuntimeManager, + additionalOptions?: DefaultEnvStreamCommandRunnerOptions +): AsyncGenerator { + // Get a `DefaultEnvStreamCommandRunnerFactory` + const factory = new DefaultEnvStreamCommandRunnerFactory(additionalOptions); + + // Get the active client + const client: TClient = await runtimeManager.getClient(); + + try { + const runner = factory.getStreamingCommandRunner(); + const generator = runner(callback(client)); + + for await (const element of generator) { + yield element; + } + } catch (err) { + if (isChildProcessError(err)) { + // If this is a child process error, alter the message to be the stderr output, if it isn't falsy + const stdErr = await factory.errAccumulator.getString(); + err.message = stdErr || err.message; + } + + throw err; + } finally { + factory.dispose(); + } +} + +class DefaultEnvStreamCommandRunnerFactory extends ShellStreamCommandRunnerFactory implements vscode.Disposable { + public readonly errAccumulator: AccumulatorStream; + + public constructor(options: TOptions) { + const errAccumulator = new AccumulatorStream(); + + super({ + ...options, + env: withDockerEnvSettings(process.env), + shell: false, + shellProvider: undefined, + stdErrPipe: errAccumulator, + strict: true, + }); + + this.errAccumulator = errAccumulator; + } + + public dispose(): void { + this.errAccumulator.destroy(); + } +} diff --git a/src/tasks/netcore/NetCoreTaskHelper.ts b/src/tasks/netcore/NetCoreTaskHelper.ts index d7cd232f..cf7a1725 100644 --- a/src/tasks/netcore/NetCoreTaskHelper.ts +++ b/src/tasks/netcore/NetCoreTaskHelper.ts @@ -242,7 +242,7 @@ export class NetCoreTaskHelper implements TaskHelper { // Try to get a container username from the image (best effort only) let userName: string | undefined; try { - const imageInspection = (await ext.runWithDefaultShell(client => + const imageInspection = (await ext.runWithDefaults(client => client.inspectImages({ imageRefs: [runOptions.image] }) ))?.[0]; userName = imageInspection?.user; diff --git a/src/tree/RefreshManager.ts b/src/tree/RefreshManager.ts index cfaab20d..520435a6 100644 --- a/src/tree/RefreshManager.ts +++ b/src/tree/RefreshManager.ts @@ -115,7 +115,7 @@ export class RefreshManager extends vscode.Disposable { const eventsUntilTimestamp = eventsSinceTimestamp + eventListenerLifetimeSeconds; try { - const eventGenerator = ext.streamWithDefaultShell(client => + const eventGenerator = ext.streamWithDefaults(client => client.getEventStream({ types: eventTypesToWatch, events: eventActionsToWatch, diff --git a/src/tree/containers/ContainerTreeItem.ts b/src/tree/containers/ContainerTreeItem.ts index e868c958..f7be29b3 100644 --- a/src/tree/containers/ContainerTreeItem.ts +++ b/src/tree/containers/ContainerTreeItem.ts @@ -101,7 +101,7 @@ export class ContainerTreeItem extends ToolTipParentTreeItem implements MultiSel } public async deleteTreeItemImpl(context: IActionContext): Promise { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeContainers({ containers: [this.containerId], force: true }) ); } @@ -147,7 +147,7 @@ export class ContainerTreeItem extends ToolTipParentTreeItem implements MultiSel public async resolveTooltipInternal(actionContext: IActionContext): Promise { actionContext.telemetry.properties.tooltipType = 'container'; - const containerInspection = (await ext.runWithDefaultShell(client => + const containerInspection = (await ext.runWithDefaults(client => client.inspectContainers({ containers: [this.containerId] }) ))?.[0]; diff --git a/src/tree/containers/ContainersTreeItem.ts b/src/tree/containers/ContainersTreeItem.ts index e3d4219c..05fa4d58 100644 --- a/src/tree/containers/ContainersTreeItem.ts +++ b/src/tree/containers/ContainersTreeItem.ts @@ -56,7 +56,7 @@ export class ContainersTreeItem extends LocalRootTreeItemBase { - const rawResults = await ext.runWithDefaultShell(client => + const rawResults = await ext.runWithDefaults(client => client.listContainers({ all: true }) ); diff --git a/src/tree/images/ImageTreeItem.ts b/src/tree/images/ImageTreeItem.ts index 1aee44fd..be5c83bc 100644 --- a/src/tree/images/ImageTreeItem.ts +++ b/src/tree/images/ImageTreeItem.ts @@ -76,7 +76,7 @@ export class ImageTreeItem extends ToolTipTreeItem { ref = this._item.id; } - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeImages({ imageRefs: [ref] }) ); } @@ -85,10 +85,10 @@ export class ImageTreeItem extends ToolTipTreeItem { actionContext.telemetry.properties.tooltipType = 'image'; // Allows some parallelization of the two commands - const imagePromise = ext.runWithDefaultShell(client => + const imagePromise = ext.runWithDefaults(client => client.inspectImages({ imageRefs: [this.imageId] }) ); - const containersPromise = ext.runWithDefaultShell(client => + const containersPromise = ext.runWithDefaults(client => client.listContainers({ imageAncestors: [this.imageId] }) ); diff --git a/src/tree/images/ImagesTreeItem.ts b/src/tree/images/ImagesTreeItem.ts index 646e8d4f..16334d88 100644 --- a/src/tree/images/ImagesTreeItem.ts +++ b/src/tree/images/ImagesTreeItem.ts @@ -67,7 +67,7 @@ export class ImagesTreeItem extends LocalRootTreeItemBase + const result = await ext.runWithDefaults(client => client.listImages(options) ); this.outdatedImageChecker.markOutdatedImages(result); diff --git a/src/tree/images/imageChecker/OutdatedImageChecker.ts b/src/tree/images/imageChecker/OutdatedImageChecker.ts index 9bb13d75..d1bd2285 100644 --- a/src/tree/images/imageChecker/OutdatedImageChecker.ts +++ b/src/tree/images/imageChecker/OutdatedImageChecker.ts @@ -89,7 +89,7 @@ export class OutdatedImageChecker { const latestImageDigest = await this.getLatestImageDigest(registry, imageNameInfo.image, imageNameInfo.tag); // 2. Compare it with the current image's value - const imageInspectInfo = (await ext.runWithDefaultShell(client => + const imageInspectInfo = (await ext.runWithDefaults(client => client.inspectImages({ imageRefs: [image.id] }) ))?.[0]; diff --git a/src/tree/networks/NetworkTreeItem.ts b/src/tree/networks/NetworkTreeItem.ts index 8860c1ee..64b1f4b0 100644 --- a/src/tree/networks/NetworkTreeItem.ts +++ b/src/tree/networks/NetworkTreeItem.ts @@ -56,7 +56,7 @@ export class NetworkTreeItem extends ToolTipTreeItem { } public async deleteTreeItemImpl(context: IActionContext): Promise { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeNetworks({ networks: [this.networkId] }) ); } @@ -65,10 +65,10 @@ export class NetworkTreeItem extends ToolTipTreeItem { actionContext.telemetry.properties.tooltipType = 'network'; // Allows some parallelization of the two commands - const networkPromise = ext.runWithDefaultShell(client => + const networkPromise = ext.runWithDefaults(client => client.inspectNetworks({ networks: [this.networkName] }) ); - const containersPromise = ext.runWithDefaultShell(client => + const containersPromise = ext.runWithDefaults(client => client.listContainers({ networks: [this.networkName] }) ); diff --git a/src/tree/networks/NetworksTreeItem.ts b/src/tree/networks/NetworksTreeItem.ts index dd939b89..416e35d4 100644 --- a/src/tree/networks/NetworksTreeItem.ts +++ b/src/tree/networks/NetworksTreeItem.ts @@ -47,7 +47,7 @@ export class NetworksTreeItem extends LocalRootTreeItemBase('networks.showBuiltInNetworks'); - let networks = await ext.runWithDefaultShell(client => + let networks = await ext.runWithDefaults(client => client.listNetworks({}) ) || []; diff --git a/src/tree/volumes/VolumeTreeItem.ts b/src/tree/volumes/VolumeTreeItem.ts index 5422d4ae..a477c14a 100644 --- a/src/tree/volumes/VolumeTreeItem.ts +++ b/src/tree/volumes/VolumeTreeItem.ts @@ -53,7 +53,7 @@ export class VolumeTreeItem extends ToolTipTreeItem implements VolumeTreeItemUse } public async deleteTreeItemImpl(context: IActionContext): Promise { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.removeVolumes({ volumes: [this.volumeName] }) ); } @@ -62,10 +62,10 @@ export class VolumeTreeItem extends ToolTipTreeItem implements VolumeTreeItemUse actionContext.telemetry.properties.tooltipType = 'volume'; // Allows some parallelization of the two commands - const volumePromise = ext.runWithDefaultShell(client => + const volumePromise = ext.runWithDefaults(client => client.inspectVolumes({ volumes: [this.volumeName] }) ); - const containersPromise = ext.runWithDefaultShell(client => + const containersPromise = ext.runWithDefaults(client => client.listContainers({ volumes: [this.volumeName] }) ); diff --git a/src/tree/volumes/VolumesTreeItem.ts b/src/tree/volumes/VolumesTreeItem.ts index c334504c..39ba30ec 100644 --- a/src/tree/volumes/VolumesTreeItem.ts +++ b/src/tree/volumes/VolumesTreeItem.ts @@ -42,7 +42,7 @@ export class VolumesTreeItem extends LocalRootTreeItemBase { - return ext.runWithDefaultShell(client => + return ext.runWithDefaults(client => client.listVolumes({}) ); } diff --git a/src/utils/RuntimeInstallStatusProvider.ts b/src/utils/RuntimeInstallStatusProvider.ts index 52cc0cf5..8bac30d8 100644 --- a/src/utils/RuntimeInstallStatusProvider.ts +++ b/src/utils/RuntimeInstallStatusProvider.ts @@ -28,7 +28,7 @@ class RuntimeInstallStatusProvider { public async isRuntimeInstalledRealTimeCheck(): Promise { try { - await ext.runWithDefaultShell(client => + await ext.runWithDefaults(client => client.checkInstall({}) ); return true; // As long as the -v command did't throw exception, assume it is installed. diff --git a/src/utils/osUtils.ts b/src/utils/osUtils.ts index 72f2f964..08bbe285 100644 --- a/src/utils/osUtils.ts +++ b/src/utils/osUtils.ts @@ -15,7 +15,7 @@ export async function getDockerOSType(): Promise { // so short-circuit the Docker call entirely. return 'linux'; } else { - const info = await ext.runWithDefaultShell(client => + const info = await ext.runWithDefaults(client => client.info({}) ); return info?.osType || 'linux';