Run most commands without a shell (#3747)
This commit is contained in:
Родитель
10de482586
Коммит
f6e55987c1
|
@ -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<VoidCommandResponse>
|
||||
);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -17,7 +17,7 @@ export async function pruneContainers(context: IActionContext): Promise<void> {
|
|||
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({})
|
||||
);
|
||||
|
||||
|
|
|
@ -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) })
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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) })
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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) })
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -17,7 +17,7 @@ export async function pruneImages(context: IActionContext): Promise<void> {
|
|||
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({})
|
||||
);
|
||||
|
||||
|
|
|
@ -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] })
|
||||
);
|
||||
|
||||
|
|
|
@ -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 })
|
||||
);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ export async function createNetwork(context: IActionContext): Promise<void> {
|
|||
}
|
||||
);
|
||||
|
||||
await ext.runWithDefaultShell(client =>
|
||||
await ext.runWithDefaults(client =>
|
||||
client.createNetwork({ name: name, driver: driverSelection.label })
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -16,7 +16,7 @@ export async function pruneNetworks(context: IActionContext): Promise<void> {
|
|||
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({})
|
||||
);
|
||||
|
||||
|
|
|
@ -17,16 +17,16 @@ export async function pruneSystem(context: IActionContext): Promise<void> {
|
|||
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({})
|
||||
);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -14,7 +14,7 @@ export async function inspectVolume(context: IActionContext, node?: VolumeTreeIt
|
|||
node = await ext.volumesTree.showTreeItemPicker<VolumeTreeItem>(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));
|
||||
|
|
|
@ -17,7 +17,7 @@ export async function pruneVolumes(context: IActionContext): Promise<void> {
|
|||
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({})
|
||||
);
|
||||
|
||||
|
|
|
@ -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<void> {
|
||||
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[] = [];
|
||||
|
|
|
@ -134,7 +134,7 @@ class ServerReadyDetector implements DockerServerReadyDetector {
|
|||
}
|
||||
|
||||
private async getHostPortForContainerPort(containerName: string, containerPort: number): Promise<number> {
|
||||
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<void> {
|
||||
try {
|
||||
const generator = ext.streamWithDefaultShell(
|
||||
const generator = ext.streamWithDefaults(
|
||||
client => client.logsForContainer({ container: this.containerName, follow: true }),
|
||||
{
|
||||
cancellationToken: this.cts.token,
|
||||
|
|
|
@ -268,7 +268,7 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
|
||||
private async copyDebuggerToContainer(context: IActionContext, containerName: string, containerDebuggerDirectory: string, containerOS: ContainerOS): Promise<void> {
|
||||
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,
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ export class ContextManager implements IContextManager, vscode.Disposable {
|
|||
}
|
||||
|
||||
public async getContexts(): Promise<ListContextItem[]> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
await ext.runWithDefaultShell(client =>
|
||||
await ext.runWithDefaults(client =>
|
||||
client.removeContexts({ contexts: [name] })
|
||||
);
|
||||
}
|
||||
|
||||
public async inspectContext(name: string): Promise<InspectContextsItem | undefined> {
|
||||
const result = await ext.runWithDefaultShell(client =>
|
||||
const result = await ext.runWithDefaults(client =>
|
||||
client.inspectContexts({ contexts: [name] })
|
||||
);
|
||||
return result?.[0];
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<string>): Record<string, string> {
|
||||
return environmentVariables.reduce<Record<string, string>>((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<string>): Record<string, string> {
|
||||
return environmentVariables.reduce<Record<string, string>>((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;
|
||||
}, {});
|
||||
}
|
||||
|
|
|
@ -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 .}}"'),
|
||||
);
|
||||
|
|
|
@ -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<TOptions extends ShellStreamCommand
|
|||
await processPromise;
|
||||
}
|
||||
|
||||
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: string[] } {
|
||||
return {
|
||||
command: commandResponse.command,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
args: Shell.getShellOrDefault(this.options.shellProvider).quote(commandResponse.args),
|
||||
};
|
||||
protected getCommandAndArgs(commandResponse: CommandResponseBase): { command: string, args: CommandLineArgs } {
|
||||
return commandResponse;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
CommandResponseBase,
|
||||
ICommandRunnerFactory,
|
||||
} from '../contracts/CommandRunner';
|
||||
import { Shell } from '../utils/spawnStreamAsync';
|
||||
import { CommandLineArgs, composeArgs, withArg, withNamedArg } from '../utils/commandLineBuilder';
|
||||
import {
|
||||
ShellStreamCommandRunnerFactory,
|
||||
ShellStreamCommandRunnerOptions,
|
||||
|
@ -22,20 +22,14 @@ export type WslShellCommandRunnerOptions = ShellStreamCommandRunnerOptions & {
|
|||
* Special case of {@link ShellStreamCommandRunnerFactory} for executing commands in a wsl distro
|
||||
*/
|
||||
export class WslShellCommandRunnerFactory extends ShellStreamCommandRunnerFactory<WslShellCommandRunnerOptions> 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 };
|
||||
}
|
||||
|
|
|
@ -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<typeof dayjsinner>) {
|
||||
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<unknown>) {
|
||||
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<typeof dayjsinner>) {
|
||||
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<unknown>) {
|
||||
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;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -141,7 +141,7 @@ export type StreamSpawnOptions = SpawnOptions & {
|
|||
|
||||
export async function spawnStreamAsync(
|
||||
command: string,
|
||||
args: Array<string>,
|
||||
args: CommandLineArgs,
|
||||
options: StreamSpawnOptions,
|
||||
): Promise<void> {
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<TClient, T> = (client: TClient) => Like<PromiseCommandResponse<T>>;
|
||||
type VoidClientCallback<TClient> = (client: TClient) => Like<VoidCommandResponse>;
|
||||
type StreamingClientCallback<TClient, T> = (client: TClient) => Like<GeneratorCommandResponse<T>>;
|
||||
|
||||
// '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<ShellStreamCommandRunnerOptions, 'env' | 'shellProvider' | 'stdErrPipe' | 'strict'>;
|
||||
|
||||
export async function runWithDefaultShellInternal<T>(callback: ClientCallback<IContainersClient, T>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<T>;
|
||||
export async function runWithDefaultShellInternal(callback: VoidClientCallback<IContainersClient>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<void>;
|
||||
export async function runWithDefaultShellInternal<T>(callback: ClientCallback<IContainersClient, T> | VoidClientCallback<IContainersClient>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<T | void> {
|
||||
return await runWithDefaultShell(
|
||||
callback,
|
||||
ext.runtimeManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
export function streamWithDefaultShellInternal<T>(callback: StreamingClientCallback<IContainersClient, T>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): AsyncGenerator<T> {
|
||||
return streamWithDefaultShell(
|
||||
callback,
|
||||
ext.runtimeManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
export async function runOrchestratorWithDefaultShellInternal<T>(callback: ClientCallback<IContainerOrchestratorClient, T>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<T>;
|
||||
export async function runOrchestratorWithDefaultShellInternal(callback: VoidClientCallback<IContainerOrchestratorClient>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<void>;
|
||||
export async function runOrchestratorWithDefaultShellInternal<T>(callback: ClientCallback<IContainerOrchestratorClient, T> | VoidClientCallback<IContainerOrchestratorClient>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): Promise<T | void> {
|
||||
return await runWithDefaultShell(
|
||||
callback,
|
||||
ext.orchestratorManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
export function streamOrchestratorWithDefaultShellInternal<T>(callback: StreamingClientCallback<IContainerOrchestratorClient, T>, additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions): AsyncGenerator<T> {
|
||||
return streamWithDefaultShell(
|
||||
callback,
|
||||
ext.orchestratorManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
async function runWithDefaultShell<TClient extends ClientIdentity, T>(
|
||||
callback: ClientCallback<TClient, T> | VoidClientCallback<TClient>,
|
||||
runtimeManager: RuntimeManager<TClient>,
|
||||
additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions
|
||||
): Promise<T | void> {
|
||||
// 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<T>);
|
||||
} 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<TClient extends ClientIdentity, T>(
|
||||
callback: StreamingClientCallback<TClient, T>,
|
||||
runtimeManager: RuntimeManager<TClient>,
|
||||
additionalOptions?: DefaultEnvShellStreamCommandRunnerOptions
|
||||
): AsyncGenerator<T> {
|
||||
// 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<TOptions extends DefaultEnvShellStreamCommandRunnerOptions> extends ShellStreamCommandRunnerFactory<ShellStreamCommandRunnerOptions> 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();
|
||||
}
|
||||
}
|
|
@ -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<TClient, T> = (client: TClient) => Like<PromiseCommandResponse<T>>;
|
||||
type VoidClientCallback<TClient> = (client: TClient) => Like<VoidCommandResponse>;
|
||||
type StreamingClientCallback<TClient, T> = (client: TClient) => Like<GeneratorCommandResponse<T>>;
|
||||
|
||||
// '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<ShellStreamCommandRunnerOptions, 'env' | 'shell' | 'shellProvider' | 'stdErrPipe' | 'strict'>;
|
||||
|
||||
export async function runWithDefaults<T>(callback: ClientCallback<IContainersClient, T>, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise<T>;
|
||||
export async function runWithDefaults(callback: VoidClientCallback<IContainersClient>, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise<void>;
|
||||
export async function runWithDefaults<T>(callback: ClientCallback<IContainersClient, T> | VoidClientCallback<IContainersClient>, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): Promise<T | void> {
|
||||
return await runWithDefaultsInternal(
|
||||
callback,
|
||||
ext.runtimeManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
export function streamWithDefaults<T>(callback: StreamingClientCallback<IContainersClient, T>, additionalOptions?: DefaultEnvStreamCommandRunnerOptions): AsyncGenerator<T> {
|
||||
return streamWithDefaultsInternal(
|
||||
callback,
|
||||
ext.runtimeManager,
|
||||
additionalOptions
|
||||
);
|
||||
}
|
||||
|
||||
async function runWithDefaultsInternal<TClient extends ClientIdentity, T>(
|
||||
callback: ClientCallback<TClient, T> | VoidClientCallback<TClient>,
|
||||
runtimeManager: RuntimeManager<TClient>,
|
||||
additionalOptions?: DefaultEnvStreamCommandRunnerOptions
|
||||
): Promise<T | void> {
|
||||
// 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<T>);
|
||||
} 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<TClient extends ClientIdentity, T>(
|
||||
callback: StreamingClientCallback<TClient, T>,
|
||||
runtimeManager: RuntimeManager<TClient>,
|
||||
additionalOptions?: DefaultEnvStreamCommandRunnerOptions
|
||||
): AsyncGenerator<T> {
|
||||
// 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<TOptions extends DefaultEnvStreamCommandRunnerOptions> extends ShellStreamCommandRunnerFactory<ShellStreamCommandRunnerOptions> 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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -101,7 +101,7 @@ export class ContainerTreeItem extends ToolTipParentTreeItem implements MultiSel
|
|||
}
|
||||
|
||||
public async deleteTreeItemImpl(context: IActionContext): Promise<void> {
|
||||
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<vscode.MarkdownString> {
|
||||
actionContext.telemetry.properties.tooltipType = 'container';
|
||||
|
||||
const containerInspection = (await ext.runWithDefaultShell(client =>
|
||||
const containerInspection = (await ext.runWithDefaults(client =>
|
||||
client.inspectContainers({ containers: [this.containerId] })
|
||||
))?.[0];
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ export class ContainersTreeItem extends LocalRootTreeItemBase<DockerContainerInf
|
|||
}
|
||||
|
||||
public async getItems(context: IActionContext): Promise<DockerContainerInfo[]> {
|
||||
const rawResults = await ext.runWithDefaultShell(client =>
|
||||
const rawResults = await ext.runWithDefaults(client =>
|
||||
client.listContainers({ all: true })
|
||||
);
|
||||
|
||||
|
|
|
@ -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] })
|
||||
);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ export class ImagesTreeItem extends LocalRootTreeItemBase<DatedDockerImage, Imag
|
|||
dangling: includeDangling ? undefined : false,
|
||||
};
|
||||
|
||||
const result = await ext.runWithDefaultShell(client =>
|
||||
const result = await ext.runWithDefaults(client =>
|
||||
client.listImages(options)
|
||||
);
|
||||
this.outdatedImageChecker.markOutdatedImages(result);
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ export class NetworkTreeItem extends ToolTipTreeItem {
|
|||
}
|
||||
|
||||
public async deleteTreeItemImpl(context: IActionContext): Promise<void> {
|
||||
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] })
|
||||
);
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ export class NetworksTreeItem extends LocalRootTreeItemBase<ListNetworkItem, Net
|
|||
const config = workspace.getConfiguration(configPrefix);
|
||||
const showBuiltInNetworks: boolean = config.get<boolean>('networks.showBuiltInNetworks');
|
||||
|
||||
let networks = await ext.runWithDefaultShell(client =>
|
||||
let networks = await ext.runWithDefaults(client =>
|
||||
client.listNetworks({})
|
||||
) || [];
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export class VolumeTreeItem extends ToolTipTreeItem implements VolumeTreeItemUse
|
|||
}
|
||||
|
||||
public async deleteTreeItemImpl(context: IActionContext): Promise<void> {
|
||||
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] })
|
||||
);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ export class VolumesTreeItem extends LocalRootTreeItemBase<ListVolumeItem, Volum
|
|||
}
|
||||
|
||||
public async getItems(context: IActionContext): Promise<ListVolumeItem[]> {
|
||||
return ext.runWithDefaultShell(client =>
|
||||
return ext.runWithDefaults(client =>
|
||||
client.listVolumes({})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class RuntimeInstallStatusProvider {
|
|||
|
||||
public async isRuntimeInstalledRealTimeCheck(): Promise<boolean> {
|
||||
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.
|
||||
|
|
|
@ -15,7 +15,7 @@ export async function getDockerOSType(): Promise<ContainerOS> {
|
|||
// 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';
|
||||
|
|
Загрузка…
Ссылка в новой задаче