Merge branch 'main' into bmw/esbuild
This commit is contained in:
Коммит
6c2b970277
|
@ -3,6 +3,8 @@ trigger:
|
|||
- main
|
||||
- rel/*
|
||||
|
||||
pr: none # Disable PR trigger
|
||||
|
||||
# Scheduled nightly build
|
||||
schedules:
|
||||
- cron: "0 0 * * *"
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,3 +1,18 @@
|
|||
## 1.26.0 - 10 July 2023
|
||||
### Added
|
||||
* Added support for debugging .NET projects with .NET SDK container build. [#3808](https://github.com/microsoft/vscode-docker/issues/3808)
|
||||
* Introduced optional status bar item displaying the current Docker context. [#3690](https://github.com/microsoft/vscode-docker/issues/3690)
|
||||
* Enabled customization of entry point for docker run tasks. [#3831](https://github.com/microsoft/vscode-docker/issues/3831)
|
||||
|
||||
### Fixed
|
||||
* Updated Dockerfile language server to ignore empty continuation lines in COPY instructions and resolve an infinite loop caused by quotes in comments for the semantic highlighter. [#3576](https://github.com/microsoft/vscode-docker/issues/3576), [#3836](https://github.com/microsoft/vscode-docker/issues/3836)
|
||||
* Resolved the failure to build Windows containers in the Build image command. [#3915](https://github.com/microsoft/vscode-docker/issues/3915)
|
||||
* Fixed the issue where .NET Debugging with Docker Compose failed to hit breakpoints. [#3912](https://github.com/microsoft/vscode-docker/issues/3912)
|
||||
|
||||
## 1.25.2 - 23 June 2023
|
||||
### Fixed
|
||||
* Fixed a potential security issue involving Markdown tooltips for containers. [#3983](https://github.com/microsoft/vscode-docker/pull/3983)
|
||||
|
||||
## 1.25.1 - 16 May 2023
|
||||
### Fixed
|
||||
* The extension was not activating when a Dockerfile was opened. [#3928](https://github.com/microsoft/vscode-docker/pull/3928)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "vscode-docker",
|
||||
"version": "1.25.5-alpha",
|
||||
"version": "1.26.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vscode-docker",
|
||||
"version": "1.25.5-alpha",
|
||||
"version": "1.26.0",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"@azure/arm-authorization": "^9.0.0",
|
||||
|
@ -22,7 +22,7 @@
|
|||
"gradle-to-js": "^2.0.1",
|
||||
"handlebars": "^4.7.7",
|
||||
"node-fetch": "^2.6.9",
|
||||
"semver": "^7.5.0",
|
||||
"semver": "^7.5.2",
|
||||
"tar": "^6.1.13",
|
||||
"tree-kill": "^1.2.2",
|
||||
"vscode-languageclient": "^8.1.0",
|
||||
|
@ -58,6 +58,15 @@
|
|||
"vscode": "^1.75.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
|
||||
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/abort-controller": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
|
||||
|
@ -1659,9 +1668,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vscode/vsce/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
|
@ -4803,17 +4812,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||
"integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
||||
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@aashutoshrathi/word-wrap": "^1.2.3",
|
||||
"deep-is": "^0.1.3",
|
||||
"fast-levenshtein": "^2.0.6",
|
||||
"levn": "^0.4.1",
|
||||
"prelude-ls": "^1.2.1",
|
||||
"type-check": "^0.4.0",
|
||||
"word-wrap": "^1.2.3"
|
||||
"type-check": "^0.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
|
@ -4888,9 +4897,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/parse-semver/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
|
@ -5434,9 +5443,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz",
|
||||
"integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz",
|
||||
"integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
|
@ -6442,14 +6451,11 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
"node_modules/wildcard": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
|
||||
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
|
|
48
package.json
48
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vscode-docker",
|
||||
"version": "1.25.5-alpha",
|
||||
"version": "1.26.0",
|
||||
"publisher": "ms-azuretools",
|
||||
"displayName": "Docker",
|
||||
"description": "Makes it easy to create, manage, and debug containerized applications.",
|
||||
|
@ -42,6 +42,10 @@
|
|||
"contributes": {
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "vscode-docker.openDockerDownloadPage",
|
||||
"when": "never"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.containers.downloadFile",
|
||||
"when": "never"
|
||||
|
@ -636,6 +640,13 @@
|
|||
{
|
||||
"type": "docker",
|
||||
"label": "Docker: Debug in Container",
|
||||
"languages": [
|
||||
"csharp",
|
||||
"razor",
|
||||
"aspnetcorerazor",
|
||||
"vb",
|
||||
"fsharp"
|
||||
],
|
||||
"configurationAttributes": {
|
||||
"launch": {
|
||||
"properties": {
|
||||
|
@ -1500,6 +1511,35 @@
|
|||
"required": [
|
||||
"dockerCompose"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dotnet-container-sdk",
|
||||
"properties": {
|
||||
"netCore": {
|
||||
"description": "%vscode-docker.debug.netCore.description%",
|
||||
"properties": {
|
||||
"appProject": {
|
||||
"type": "string",
|
||||
"description": "%vscode-docker.debug.netCore.appProject%"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"appProject"
|
||||
]
|
||||
},
|
||||
"dockerRun": {
|
||||
"description": "%vscode-docker.tasks.dotnet-container-sdk.dockerRun.description%",
|
||||
"properties": {
|
||||
"containerName": {
|
||||
"type": "string",
|
||||
"description": "%vscode-docker.tasks.dotnet-container-sdk.dockerRun.containerName%"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"containerName"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
|
@ -2290,8 +2330,8 @@
|
|||
"category": "%vscode-docker.commands.category.docker%"
|
||||
},
|
||||
{
|
||||
"command": "vscode-docker.installDocker",
|
||||
"title": "%vscode-docker.commands.installDocker%",
|
||||
"command": "vscode-docker.openDockerDownloadPage",
|
||||
"title": "%vscode-docker.commands.openDockerDownloadPage%",
|
||||
"category": "%vscode-docker.commands.category.docker%"
|
||||
},
|
||||
{
|
||||
|
@ -2993,7 +3033,7 @@
|
|||
"gradle-to-js": "^2.0.1",
|
||||
"handlebars": "^4.7.7",
|
||||
"node-fetch": "^2.6.9",
|
||||
"semver": "^7.5.0",
|
||||
"semver": "^7.5.2",
|
||||
"tar": "^6.1.13",
|
||||
"tree-kill": "^1.2.2",
|
||||
"vscode-languageclient": "^8.1.0",
|
||||
|
|
|
@ -123,6 +123,8 @@
|
|||
"vscode-docker.tasks.docker-compose.dockerCompose.envFile.description": "File of environment variables read in and applied to the Docker containers.",
|
||||
"vscode-docker.tasks.docker-compose.dockerCompose.files.description": "The docker-compose files to include, in order.",
|
||||
"vscode-docker.tasks.docker-compose.dockerCompose.projectName.description": "Alternate project name to use when naming and labeling Docker objects. If using an alternate project name when composing up, the same project name must be specified when composing down.",
|
||||
"vscode-docker.tasks.dotnet-container-sdk.dockerRun.description": "Options for running the Docker container used for debugging.",
|
||||
"vscode-docker.tasks.dotnet-container-sdk.dockerRun.containerName": "Name of the container used for debugging.",
|
||||
"vscode-docker.config.docker.promptForRegistryWhenPushingImages": "Prompt for registry selection if the image is not explicitly tagged.",
|
||||
"vscode-docker.config.template.build.template": "The command template.",
|
||||
"vscode-docker.config.template.build.label": "The label displayed to the user.",
|
||||
|
@ -247,7 +249,7 @@
|
|||
"vscode-docker.commands.images.runInteractive": "Run Interactive",
|
||||
"vscode-docker.commands.images.tag": "Tag...",
|
||||
"vscode-docker.commands.images.copyFullTag": "Copy Full Tag",
|
||||
"vscode-docker.commands.installDocker": "Install Docker",
|
||||
"vscode-docker.commands.openDockerDownloadPage": "Learn More About Installing Docker Desktop",
|
||||
"vscode-docker.commands.networks.configureExplorer": "Configure Explorer...",
|
||||
"vscode-docker.commands.networks.create": "Create...",
|
||||
"vscode-docker.commands.networks.inspect": "Inspect",
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
<Project>
|
||||
<!-- All the relevant info is in root-level PropertyGroups, so there are no dependent targets to make this work -->
|
||||
<Target Name="GetProjectProperties">
|
||||
<PropertyGroup>
|
||||
<GetProjectPropertiesDependsOn Condition=" '$(SDKContainerSupportEnabled)' == 'true' ">$(GetProjectPropertiesDependsOn);ComputeContainerConfig;</GetProjectPropertiesDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="GetProjectProperties" DependsOnTargets="$(GetProjectPropertiesDependsOn)">
|
||||
<PropertyGroup>
|
||||
<InferImageName>$(ContainerRepository)</InferImageName>
|
||||
<InferImageName Condition=" '$(InferImageName)' == '' ">$(ContainerImageName)</InferImageName>
|
||||
</PropertyGroup>
|
||||
<WriteLinesToFile
|
||||
File="$(InfoOutputPath)"
|
||||
Lines="$(AssemblyName).dll
|
||||
$(TargetFramework)$(TargetFrameworks.Split(';')[0])
|
||||
$(OutputPath)$(AssemblyName).dll"
|
||||
$(OutputPath)$(AssemblyName).dll
|
||||
$(ContainerWorkingDirectory)/$(AssemblyName).dll
|
||||
$(SDKContainerSupportEnabled)
|
||||
$(InferImageName)"
|
||||
Overwrite="True" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { TaskCommandRunnerFactory } from '../runtimes/runners/TaskCommandRunnerFactory';
|
||||
import { runtimeInstallStatusProvider } from '../utils/RuntimeInstallStatusProvider';
|
||||
import { streamToFile } from '../utils/httpRequest';
|
||||
import { getTempFileName, isArm64Mac, isLinux } from '../utils/osUtils';
|
||||
|
||||
export abstract class DockerInstallerBase {
|
||||
protected abstract downloadUrl: string;
|
||||
protected abstract fileExtension: string;
|
||||
protected abstract getInstallCommand(fileName: string): string;
|
||||
|
||||
public async downloadAndInstallDocker(context: IActionContext): Promise<void> {
|
||||
const shouldInstall: boolean = await this.preInstallCheck();
|
||||
if (shouldInstall) {
|
||||
const downloadingMessage: string = vscode.l10n.t('Downloading Docker installer...');
|
||||
const installationMessage: string = vscode.l10n.t('The Docker Desktop installation is started. Complete the installation and then start Docker Desktop.');
|
||||
let downloadedFileName: string;
|
||||
|
||||
context.telemetry.properties.stage = 'download';
|
||||
try {
|
||||
downloadedFileName = await vscode.window.withProgress(
|
||||
{ location: vscode.ProgressLocation.Notification, title: downloadingMessage },
|
||||
async () => this.downloadInstaller());
|
||||
} catch (error) {
|
||||
const message = vscode.l10n.t('Downloading the Docker Desktop installer failed. Do you want to manually download and install?');
|
||||
const title = vscode.l10n.t('Download');
|
||||
this.handleError(context, message, title, this.downloadUrl);
|
||||
throw error;
|
||||
}
|
||||
|
||||
context.telemetry.properties.stage = 'install';
|
||||
const command = this.getInstallCommand(downloadedFileName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
vscode.window.showInformationMessage(installationMessage);
|
||||
try {
|
||||
await this.install(context, downloadedFileName, command);
|
||||
} catch (error) {
|
||||
const message = `${vscode.l10n.t('Docker Desktop installation failed')}. ${error}`;
|
||||
const title = vscode.l10n.t('Install Instruction');
|
||||
this.handleError(context, message, title, 'https://aka.ms/AA37qtj');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async preInstallCheck(): Promise<boolean> {
|
||||
let proceedInstall = true;
|
||||
if (await runtimeInstallStatusProvider.isRuntimeInstalledRealTimeCheck()) {
|
||||
const reinstallMessage = vscode.l10n.t('Docker Desktop is already installed. Would you like to reinstall?');
|
||||
const install = vscode.l10n.t('Reinstall');
|
||||
const response = await vscode.window.showInformationMessage(reinstallMessage, ...[install]);
|
||||
proceedInstall = response !== undefined;
|
||||
}
|
||||
|
||||
return proceedInstall;
|
||||
}
|
||||
|
||||
private async downloadInstaller(): Promise<string> {
|
||||
const fileName = `${getTempFileName()}.${this.fileExtension}`;
|
||||
await streamToFile(this.downloadUrl, fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private handleError(context: IActionContext, message: string, title: string, url: string): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
vscode.window.showErrorMessage(message, { title: title }).then(response => { if (response) { vscode.env.openExternal(vscode.Uri.parse(url)); } });
|
||||
context.errorHandling.suppressReportIssue = true;
|
||||
context.errorHandling.suppressDisplay = true;
|
||||
}
|
||||
|
||||
protected abstract install(context: IActionContext, fileName: string, cmd: string): Promise<void>;
|
||||
}
|
||||
|
||||
export class WindowsDockerInstaller extends DockerInstallerBase {
|
||||
protected downloadUrl: string = 'https://aka.ms/download-docker-windows-vscode';
|
||||
protected fileExtension: string = 'exe';
|
||||
protected getInstallCommand(fileName: string): string {
|
||||
// Windows require double quote.
|
||||
return `"${fileName}"`;
|
||||
}
|
||||
|
||||
protected async install(context: IActionContext, fileName: string): Promise<void> {
|
||||
const title = vscode.l10n.t('Docker Install');
|
||||
const command = this.getInstallCommand(fileName);
|
||||
|
||||
const taskCRF = new TaskCommandRunnerFactory({
|
||||
taskName: title,
|
||||
});
|
||||
|
||||
await taskCRF.getCommandRunner()({
|
||||
command: command,
|
||||
args: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class MacDockerInstaller extends DockerInstallerBase {
|
||||
protected downloadUrl: string = isArm64Mac() ? 'https://aka.ms/download-docker-arm-mac-vscode' : 'https://aka.ms/download-docker-mac-vscode';
|
||||
protected fileExtension: string = 'dmg';
|
||||
protected getInstallCommand(fileName: string): string {
|
||||
return `chmod +x '${fileName}' && open '${fileName}'`;
|
||||
}
|
||||
|
||||
protected async install(context: IActionContext, fileName: string): Promise<void> {
|
||||
const title = vscode.l10n.t('Docker Install');
|
||||
const command = this.getInstallCommand(fileName);
|
||||
|
||||
const taskCRF = new TaskCommandRunnerFactory({
|
||||
taskName: title,
|
||||
});
|
||||
|
||||
await taskCRF.getCommandRunner()({
|
||||
command: command,
|
||||
args: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function showDockerInstallNotification(): Promise<void> {
|
||||
const installMessage = isLinux() ?
|
||||
vscode.l10n.t('Docker is not installed. Would you like to learn more about installing Docker?') :
|
||||
vscode.l10n.t('Docker Desktop is not installed. Would you like to install it?');
|
||||
|
||||
const learnMore = vscode.l10n.t('Learn more');
|
||||
const install = vscode.l10n.t('Install');
|
||||
|
||||
const confirmationPrompt: vscode.MessageItem = isLinux() ? { title: learnMore } : { title: install };
|
||||
const response = await vscode.window.showInformationMessage(installMessage, ...[confirmationPrompt]);
|
||||
if (response) {
|
||||
await vscode.commands.executeCommand('vscode-docker.installDocker');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IActionContext } from '@microsoft/vscode-azext-utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { isMac, isWindows } from '../utils/osUtils';
|
||||
import { MacDockerInstaller, WindowsDockerInstaller } from './dockerInstaller';
|
||||
|
||||
export async function installDocker(context: IActionContext): Promise<void> {
|
||||
if (isWindows()) {
|
||||
await (new WindowsDockerInstaller()).downloadAndInstallDocker(context);
|
||||
} else if (isMac()) {
|
||||
await (new MacDockerInstaller()).downloadAndInstallDocker(context);
|
||||
} else {
|
||||
await vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/download-docker-linux-vscode'));
|
||||
}
|
||||
}
|
|
@ -44,14 +44,12 @@ import { runAzureCliImage } from "./images/runAzureCliImage";
|
|||
import { runImage, runImageInteractive } from "./images/runImage";
|
||||
import { hideDanglingImages, setInitialDanglingContextValue, showDanglingImages } from "./images/showDanglingImages";
|
||||
import { tagImage } from "./images/tagImage";
|
||||
import { installDocker } from "./installDocker";
|
||||
import { configureNetworksExplorer } from "./networks/configureNetworksExplorer";
|
||||
import { createNetwork } from "./networks/createNetwork";
|
||||
import { inspectNetwork } from "./networks/inspectNetwork";
|
||||
import { pruneNetworks } from "./networks/pruneNetworks";
|
||||
import { removeNetwork } from "./networks/removeNetwork";
|
||||
import { pruneSystem } from "./pruneSystem";
|
||||
import { registerLocalCommand } from "./registerLocalCommand";
|
||||
import { registerWorkspaceCommand } from "./registerWorkspaceCommand";
|
||||
import { createAzureRegistry } from "./registries/azure/createAzureRegistry";
|
||||
import { deleteAzureRegistry } from "./registries/azure/deleteAzureRegistry";
|
||||
|
@ -76,6 +74,7 @@ import { logOutOfDockerCli } from "./registries/logOutOfDockerCli";
|
|||
import { pullImageFromRepository, pullRepository } from "./registries/pullImages";
|
||||
import { reconnectRegistry } from "./registries/reconnectRegistry";
|
||||
import { registryHelp } from "./registries/registryHelp";
|
||||
import { openDockerDownloadPage } from "./showDockerLearnMoreNotification";
|
||||
import { configureVolumesExplorer } from "./volumes/configureVolumesExplorer";
|
||||
import { inspectVolume } from "./volumes/inspectVolume";
|
||||
import { pruneVolumes } from "./volumes/pruneVolumes";
|
||||
|
@ -206,8 +205,7 @@ export function registerCommands(): void {
|
|||
registerCommand('vscode-docker.contexts.remove', removeDockerContext);
|
||||
registerCommand('vscode-docker.contexts.use', useDockerContext);
|
||||
|
||||
registerLocalCommand('vscode-docker.installDocker', installDocker);
|
||||
|
||||
registerCommand('vscode-docker.openDockerDownloadPage', openDockerDownloadPage);
|
||||
registerCommand('vscode-docker.help', help);
|
||||
registerCommand('vscode-docker.help.openWalkthrough', () => commands.executeCommand('workbench.action.openWalkthrough', 'ms-azuretools.vscode-docker#dockerStart'));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { isMac, isWindows } from '../utils/osUtils';
|
||||
|
||||
export async function showDockerLearnMoreNotification(): Promise<void> {
|
||||
const learnMoreMessage = vscode.l10n.t('Docker is not installed. Would you like to learn more about installing Docker?');
|
||||
const confirmationPrompt = vscode.l10n.t('Learn more');
|
||||
|
||||
const response = await vscode.window.showInformationMessage(learnMoreMessage, ...[confirmationPrompt]);
|
||||
if (response) {
|
||||
await openDockerDownloadPage();
|
||||
}
|
||||
}
|
||||
|
||||
export async function openDockerDownloadPage(): Promise<void> {
|
||||
if (isWindows()) {
|
||||
await vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/vscode/docker-windows-download'));
|
||||
} else if (isMac()) {
|
||||
await vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/vscode/docker-mac-download'));
|
||||
} else {
|
||||
await vscode.env.openExternal(vscode.Uri.parse('https://aka.ms/download-docker-linux-vscode'));
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ export const DOCKERFILE_GLOB_PATTERN = '**/{*.[dD][oO][cC][kK][eE][rR][fF][iI][l
|
|||
export const YAML_GLOB_PATTERN = '**/*.{[yY][aA][mM][lL],[yY][mM][lL]}';
|
||||
export const CSPROJ_GLOB_PATTERN = '**/*.{[cC][sS][pP][rR][oO][jJ]}';
|
||||
export const FSPROJ_GLOB_PATTERN = '**/*.{[fF][sS][pP][rR][oO][jJ]}';
|
||||
export const VBPROJ_GLOB_PATTERN = '**/*.{[vV][bB][pP][rR][oO][jJ]}';
|
||||
|
||||
// File search max ammout
|
||||
export const FILE_SEARCH_MAX_RESULT = 1000;
|
||||
|
|
|
@ -9,9 +9,10 @@ import { DockerRunTaskDefinition } from '../tasks/DockerRunTaskProvider';
|
|||
import { DockerTaskScaffoldContext, getDefaultContainerName } from '../tasks/TaskHelper';
|
||||
import { DockerServerReadyAction } from './DockerDebugConfigurationBase';
|
||||
import { DockerDebugConfiguration, DockerDebugConfigurationProvider } from './DockerDebugConfigurationProvider';
|
||||
import { DockerPlatform } from './DockerPlatformHelper';
|
||||
import { DockerPlatform } from './DockerDebugPlatformHelper';
|
||||
import { registerServerReadyAction } from './DockerServerReadyAction';
|
||||
import { netCoreDebugHelper } from './netcore/NetCoreDebugHelper';
|
||||
import { netSdkDebugHelper } from './netSdk/NetSdkDebugHelper';
|
||||
import { nodeDebugHelper } from './node/NodeDebugHelper';
|
||||
import { pythonDebugHelper } from './python/PythonDebugHelper';
|
||||
|
||||
|
@ -40,6 +41,7 @@ export interface ResolvedDebugConfiguration extends DebugConfiguration {
|
|||
export interface DebugHelper {
|
||||
provideDebugConfigurations(context: DockerDebugScaffoldContext): Promise<DockerDebugConfiguration[]>;
|
||||
resolveDebugConfiguration(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<ResolvedDebugConfiguration | undefined>;
|
||||
afterResolveDebugConfiguration?(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<void>;
|
||||
}
|
||||
|
||||
export function registerDebugProvider(ctx: ExtensionContext): void {
|
||||
|
@ -51,6 +53,7 @@ export function registerDebugProvider(ctx: ExtensionContext): void {
|
|||
netCore: netCoreDebugHelper,
|
||||
node: nodeDebugHelper,
|
||||
python: pythonDebugHelper,
|
||||
netSdk: netSdkDebugHelper
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, registerEvent } from '@microsoft/vscode-azext-utils';
|
||||
import { CancellationToken, commands, debug, DebugConfiguration, DebugConfigurationProvider, DebugSession, l10n, MessageItem, ProviderResult, window, workspace, WorkspaceFolder } from 'vscode';
|
||||
import { DockerOrchestration } from '../constants';
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, registerEvent, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import { CancellationToken, commands, debug, DebugConfiguration, DebugConfigurationProvider, DebugSession, l10n, ProviderResult, workspace, WorkspaceFolder } from 'vscode';
|
||||
import { CSPROJ_GLOB_PATTERN, DockerOrchestration, FSPROJ_GLOB_PATTERN } from '../constants';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { getAssociatedDockerRunTask } from '../tasks/TaskHelper';
|
||||
import { resolveFilesOfPattern } from '../utils/quickPickFile';
|
||||
import { DebugHelper, DockerDebugContext, ResolvedDebugConfiguration } from './DebugHelper';
|
||||
import { DockerPlatform, getPlatform } from './DockerPlatformHelper';
|
||||
import { DockerPlatform, getDebugPlatform } from './DockerDebugPlatformHelper';
|
||||
import { NetCoreDockerDebugConfiguration } from './netcore/NetCoreDebugHelper';
|
||||
import { netSdkDebugHelper } from './netSdk/NetSdkDebugHelper';
|
||||
import { NodeDockerDebugConfiguration } from './node/NodeDebugHelper';
|
||||
|
||||
export interface DockerDebugConfiguration extends NetCoreDockerDebugConfiguration, NodeDockerDebugConfiguration {
|
||||
|
@ -42,21 +44,14 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi
|
|||
}
|
||||
|
||||
public provideDebugConfigurations(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult<DebugConfiguration[]> {
|
||||
const add: MessageItem = { title: l10n.t('Add Docker Files') };
|
||||
|
||||
// Prompt them to add Docker files since they probably haven't
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
window.showErrorMessage(
|
||||
l10n.t('To debug in a Docker container on supported platforms, use the command "Docker: Add Docker Files to Workspace", or click "Add Docker Files".'),
|
||||
...[add])
|
||||
.then((result) => {
|
||||
if (result === add) {
|
||||
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
|
||||
commands.executeCommand('vscode-docker.configure');
|
||||
}
|
||||
});
|
||||
return callWithTelemetryAndErrorHandling(
|
||||
'provideDebugConfigurations',
|
||||
async (actionContext: IActionContext) => {
|
||||
return this.handleEmptyDebugConfig(folder, actionContext);
|
||||
}
|
||||
);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public resolveDebugConfiguration(folder: WorkspaceFolder | undefined, debugConfiguration: DockerDebugConfiguration, token?: CancellationToken): ProviderResult<DebugConfiguration | undefined> {
|
||||
|
@ -75,17 +70,22 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi
|
|||
}
|
||||
}
|
||||
|
||||
if (debugConfiguration.type === undefined) {
|
||||
// If type is undefined, they may be doing F5 without creating any real launch.json, which won't work
|
||||
// VSCode subsequently will call provideDebugConfigurations which will show an error message
|
||||
return null;
|
||||
if (Object.keys(debugConfiguration).length === 0) {
|
||||
|
||||
const newlyCreatedDebugConfig = await this.handleEmptyDebugConfig(folder, actionContext);
|
||||
// if there is no debugConfiguration, we should return undefined to exit the debug session
|
||||
if (newlyCreatedDebugConfig.length === 0 || !newlyCreatedDebugConfig[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
debugConfiguration = newlyCreatedDebugConfig[0];
|
||||
}
|
||||
|
||||
if (!debugConfiguration.request) {
|
||||
throw new Error(l10n.t('The property "request" must be specified in the debug config.'));
|
||||
}
|
||||
|
||||
const debugPlatform = getPlatform(debugConfiguration);
|
||||
const debugPlatform = getDebugPlatform(debugConfiguration);
|
||||
actionContext.telemetry.properties.dockerPlatform = debugPlatform;
|
||||
actionContext.telemetry.properties.orchestration = 'single' as DockerOrchestration; // TODO: docker-compose, when support is added
|
||||
|
||||
|
@ -114,6 +114,7 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi
|
|||
await this.removeDebugContainerIfNeeded(context.actionContext, resolvedConfiguration);
|
||||
}
|
||||
|
||||
await helper.afterResolveDebugConfiguration?.(context, originalConfiguration);
|
||||
return resolvedConfiguration;
|
||||
}
|
||||
|
||||
|
@ -170,4 +171,32 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user has an empty debug launch.json, then we will:
|
||||
* 1. check if it's a .NET Core project, if so, we will provide .NET Core debug configurations
|
||||
* 2. otherwise, we will scaffold docker files
|
||||
*/
|
||||
private async handleEmptyDebugConfig(folder: WorkspaceFolder, actionContext: IActionContext): Promise<DockerDebugConfiguration[]> {
|
||||
|
||||
// NOTE: We can not determine the language from `DockerDebugContext`, so we need to check the
|
||||
// type of files inside the folder here to determine the language.
|
||||
|
||||
// check if it's a .NET Core project
|
||||
const csProjUris = await resolveFilesOfPattern(folder, [CSPROJ_GLOB_PATTERN, FSPROJ_GLOB_PATTERN]);
|
||||
if (csProjUris) {
|
||||
return await netSdkDebugHelper.provideDebugConfigurations(
|
||||
{
|
||||
actionContext,
|
||||
dockerfile: undefined,
|
||||
folder: folder
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// for now, we scaffold docker files
|
||||
await commands.executeCommand('vscode-docker.configure');
|
||||
throw new UserCancelledError();
|
||||
}
|
||||
// TODO: (potentially) in the future, we can add more support for ambient tasks for other types of projects
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,14 @@
|
|||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export type DockerPlatform = 'netCore' | 'node' | 'python';
|
||||
import { DockerDebugConfiguration } from "./DockerDebugConfigurationProvider";
|
||||
|
||||
interface DockerPlatformConfiguration {
|
||||
platform?: DockerPlatform;
|
||||
netCore?: unknown;
|
||||
node?: unknown;
|
||||
python?: unknown;
|
||||
}
|
||||
|
||||
export function getPlatform<T extends DockerPlatformConfiguration>(configuration: T): DockerPlatform | undefined {
|
||||
export type DockerPlatform = 'netCore' | 'node' | 'python' | 'netSdk';
|
||||
|
||||
export function getDebugPlatform(configuration: DockerDebugConfiguration): DockerPlatform | undefined {
|
||||
if (configuration.platform === 'netCore' || configuration.netCore !== undefined) {
|
||||
return 'netCore';
|
||||
return configuration.netCore?.buildWithSdk ? 'netSdk' : 'netCore';
|
||||
} else if (configuration.platform === 'node' || configuration.node !== undefined) {
|
||||
return 'node';
|
||||
} else if (configuration.platform === 'python' || configuration.python !== undefined) {
|
|
@ -0,0 +1,144 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from "path";
|
||||
import { WorkspaceFolder, commands, l10n, tasks } from "vscode";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { NetChooseBuildTypeContext, netContainerBuild } from "../../scaffolding/wizard/net/NetContainerBuild";
|
||||
import { AllNetContainerBuildOptions, NetContainerBuildOptionsKey } from "../../scaffolding/wizard/net/NetSdkChooseBuildStep";
|
||||
import { NetSdkRunTaskDefinition, netSdkRunTaskProvider } from "../../tasks/netSdk/NetSdkRunTaskProvider";
|
||||
import { normalizeArchitectureToRidArchitecture, normalizeOsToRidOs } from "../../tasks/netSdk/netSdkTaskUtils";
|
||||
import { NetCoreTaskHelper } from "../../tasks/netcore/NetCoreTaskHelper";
|
||||
import { getNetCoreProjectInfo } from "../../utils/netCoreUtils";
|
||||
import { getDockerOSType } from "../../utils/osUtils";
|
||||
import { PlatformOS } from "../../utils/platform";
|
||||
import { resolveVariables, unresolveWorkspaceFolder } from "../../utils/resolveVariables";
|
||||
import { DockerDebugContext, DockerDebugScaffoldContext, ResolvedDebugConfiguration, inferContainerName } from "../DebugHelper";
|
||||
import { DockerDebugConfiguration } from "../DockerDebugConfigurationProvider";
|
||||
import { NetCoreDebugHelper, NetCoreDebugScaffoldingOptions, NetCoreProjectProperties } from "../netcore/NetCoreDebugHelper";
|
||||
|
||||
interface NetSdkProjectProperties extends NetCoreProjectProperties {
|
||||
containerWorkingDirectory: string;
|
||||
isSdkContainerSupportEnabled: boolean;
|
||||
imageName: string;
|
||||
}
|
||||
|
||||
export class NetSdkDebugHelper extends NetCoreDebugHelper {
|
||||
|
||||
public override async provideDebugConfigurations(context: DockerDebugScaffoldContext, options?: NetCoreDebugScaffoldingOptions): Promise<DockerDebugConfiguration[]> {
|
||||
const configurations: DockerDebugConfiguration[] = [];
|
||||
|
||||
const netCoreBuildContext: NetChooseBuildTypeContext = {
|
||||
...context.actionContext,
|
||||
scaffoldType: 'debugging',
|
||||
workspaceFolder: context.folder,
|
||||
};
|
||||
|
||||
await netContainerBuild(netCoreBuildContext); // prompt user whether to use .NET container SDK build
|
||||
if (netCoreBuildContext?.containerBuildOption === AllNetContainerBuildOptions[1]) {
|
||||
options = options || {};
|
||||
options.appProject = options.appProject || await NetCoreTaskHelper.inferAppProject(context); // This method internally checks the user-defined input first
|
||||
|
||||
configurations.push({
|
||||
name: 'Docker .NET Container SDK Launch',
|
||||
type: 'docker',
|
||||
request: 'launch',
|
||||
netCore: {
|
||||
appProject: unresolveWorkspaceFolder(options.appProject, context.folder),
|
||||
buildWithSdk: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await commands.executeCommand('vscode-docker.configure');
|
||||
}
|
||||
|
||||
return configurations;
|
||||
}
|
||||
|
||||
public override async resolveDebugConfiguration(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<ResolvedDebugConfiguration | undefined> {
|
||||
try {
|
||||
return await super.resolveDebugConfiguration(context, debugConfiguration);
|
||||
} catch (error) {
|
||||
await ext.context.workspaceState.update(NetContainerBuildOptionsKey, '');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async afterResolveDebugConfiguration(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<void> {
|
||||
const runDefinition: Omit<NetSdkRunTaskDefinition, "type"> = {
|
||||
netCore: {
|
||||
appProject: debugConfiguration.netCore.appProject,
|
||||
},
|
||||
dockerRun: {
|
||||
image: context.runDefinition.dockerRun.image,
|
||||
}
|
||||
};
|
||||
|
||||
const { task, promise } = netSdkRunTaskProvider.createNetSdkRunTask(runDefinition);
|
||||
await tasks.executeTask(task);
|
||||
await promise;
|
||||
}
|
||||
|
||||
protected override async loadExternalInfo(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<{ configureSsl: boolean, containerName: string, platformOS: PlatformOS }> {
|
||||
const projectProperties = await this.getProjectProperties(debugConfiguration, context.folder);
|
||||
debugConfiguration.netCore.appOutput = await this.normalizeAppOutput(projectProperties.containerWorkingDirectory, projectProperties.isSdkContainerSupportEnabled);
|
||||
context.runDefinition = {
|
||||
...context.runDefinition,
|
||||
dockerRun: {
|
||||
containerName: inferContainerName(debugConfiguration, context, projectProperties.imageName, "dev"),
|
||||
image: projectProperties.imageName,
|
||||
},
|
||||
netCore: {
|
||||
enableDebugging: true,
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
configureSsl: false,
|
||||
containerName: context.runDefinition.dockerRun.containerName,
|
||||
platformOS: await getDockerOSType() === "windows" ? 'Windows' : 'Linux',
|
||||
};
|
||||
}
|
||||
|
||||
protected override inferAppContainerOutput(appOutput: string, platformOS: PlatformOS): string {
|
||||
return appOutput;
|
||||
}
|
||||
|
||||
protected override async getProjectProperties(debugConfiguration: DockerDebugConfiguration, folder?: WorkspaceFolder): Promise<NetSdkProjectProperties> {
|
||||
const ridOS = await normalizeOsToRidOs();
|
||||
const ridArchitecture = await normalizeArchitectureToRidArchitecture();
|
||||
const additionalProperties = `/p:ContainerRuntimeIdentifier="${ridOS}-${ridArchitecture}"`;
|
||||
const resolvedAppProject = resolveVariables(debugConfiguration.netCore?.appProject, folder);
|
||||
|
||||
const projectInfo = await getNetCoreProjectInfo('GetProjectProperties', resolvedAppProject, additionalProperties);
|
||||
|
||||
if (projectInfo.length < 6 || !projectInfo[5]) {
|
||||
throw new Error(l10n.t("Your current project configuration or .NET SDK version doesn't support SDK Container build. Please choose a compatible project or update .NET SDK."));
|
||||
}
|
||||
|
||||
const projectProperties: NetSdkProjectProperties = {
|
||||
assemblyName: projectInfo[0],
|
||||
targetFramework: projectInfo[1],
|
||||
appOutput: projectInfo[2],
|
||||
containerWorkingDirectory: projectInfo[3],
|
||||
isSdkContainerSupportEnabled: projectInfo[4] === 'true',
|
||||
imageName: projectInfo[5],
|
||||
};
|
||||
|
||||
return projectProperties;
|
||||
}
|
||||
|
||||
private async normalizeAppOutput(unnormalizedContainerWorkingDirectory: string, isSdkContainerSupportEnabled: boolean): Promise<string> {
|
||||
if (isSdkContainerSupportEnabled) {
|
||||
return await getDockerOSType() === 'windows' // fourth is output path
|
||||
? path.win32.normalize(unnormalizedContainerWorkingDirectory)
|
||||
: path.posix.normalize(unnormalizedContainerWorkingDirectory);
|
||||
} else {
|
||||
throw new Error(l10n.t("Your current project configuration or .NET SDK version doesn't support SDK Container build. Please choose a compatible project or update .NET SDK."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const netSdkDebugHelper = new NetSdkDebugHelper();
|
|
@ -24,6 +24,7 @@ import { VsDbgType, installDebuggersIfNecessary, vsDbgInstallBasePath } from './
|
|||
export interface NetCoreDebugOptions extends NetCoreTaskOptions {
|
||||
appOutput?: string;
|
||||
debuggerPath?: string;
|
||||
buildWithSdk?: boolean;
|
||||
}
|
||||
|
||||
export interface NetCoreDockerDebugConfiguration extends DebugConfiguration {
|
||||
|
@ -34,6 +35,12 @@ export interface NetCoreDebugScaffoldingOptions {
|
|||
appProject?: string;
|
||||
}
|
||||
|
||||
export interface NetCoreProjectProperties {
|
||||
assemblyName: string;
|
||||
targetFramework: string;
|
||||
appOutput: string;
|
||||
}
|
||||
|
||||
export class NetCoreDebugHelper implements DebugHelper {
|
||||
public async provideDebugConfigurations(context: DockerDebugScaffoldContext, options?: NetCoreDebugScaffoldingOptions): Promise<DockerDebugConfiguration[]> {
|
||||
options = options || {};
|
||||
|
@ -68,7 +75,7 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
debugConfiguration.netCore.appProject = await NetCoreTaskHelper.inferAppProject(context, debugConfiguration.netCore); // This method internally checks the user-defined input first
|
||||
|
||||
const { configureSsl, containerName, platformOS } = await this.loadExternalInfo(context, debugConfiguration);
|
||||
const appOutput = await this.inferAppOutput(debugConfiguration.netCore);
|
||||
const appOutput = debugConfiguration.netCore?.appOutput || await this.inferAppOutput(debugConfiguration);
|
||||
if (context.cancellationToken && context.cancellationToken.isCancellationRequested) {
|
||||
// inferAppOutput is slow, give a chance to cancel
|
||||
return undefined;
|
||||
|
@ -90,7 +97,7 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
|
||||
const additionalProbingPathsArgs = NetCoreDebugHelper.getAdditionalProbingPathsArgs(platformOS);
|
||||
|
||||
const containerAppOutput = NetCoreDebugHelper.getContainerAppOutput(debugConfiguration, appOutput, platformOS);
|
||||
const containerAppOutput = this.inferAppContainerOutput(appOutput, platformOS);
|
||||
|
||||
const dockerServerReadyAction = resolveDockerServerReadyAction(
|
||||
debugConfiguration,
|
||||
|
@ -176,16 +183,20 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
};
|
||||
}
|
||||
|
||||
private async inferAppOutput(helperOptions: NetCoreDebugOptions): Promise<string> {
|
||||
const projectInfo = await getNetCoreProjectInfo('GetProjectProperties', helperOptions.appProject);
|
||||
if (projectInfo.length < 3) {
|
||||
throw new Error(l10n.t('Unable to determine assembly output path.'));
|
||||
}
|
||||
|
||||
return projectInfo[2]; // First line is assembly name, second is target framework, third+ are output path(s)
|
||||
protected async inferAppOutput(debugConfiguration: DockerDebugConfiguration): Promise<string> {
|
||||
const projectProperties = await this.getProjectProperties(debugConfiguration);
|
||||
return projectProperties.appOutput;
|
||||
}
|
||||
|
||||
private async loadExternalInfo(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<{ configureSsl: boolean, containerName: string, platformOS: PlatformOS }> {
|
||||
protected inferAppContainerOutput(appOutput: string, platformOS: PlatformOS): string {
|
||||
const result = platformOS === 'Windows' ?
|
||||
path.win32.join('C:\\app', appOutput) :
|
||||
path.posix.join('/app', appOutput);
|
||||
|
||||
return pathNormalize(result, platformOS);
|
||||
}
|
||||
|
||||
protected async loadExternalInfo(context: DockerDebugContext, debugConfiguration: DockerDebugConfiguration): Promise<{ configureSsl: boolean, containerName: string, platformOS: PlatformOS }> {
|
||||
const associatedTask = context.runDefinition;
|
||||
|
||||
return {
|
||||
|
@ -195,6 +206,23 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
};
|
||||
}
|
||||
|
||||
protected async getProjectProperties(debugConfiguration: DockerDebugConfiguration): Promise<NetCoreProjectProperties> {
|
||||
const projectInfo = await getNetCoreProjectInfo('GetProjectProperties', debugConfiguration.netCore?.appProject);
|
||||
|
||||
if (projectInfo.length < 3) {
|
||||
throw new Error(l10n.t('Unable to determine assembly output path.'));
|
||||
}
|
||||
|
||||
// First line is assembly name, second is target framework, third+ are output path(s)
|
||||
const projectProperties: NetCoreProjectProperties = {
|
||||
assemblyName: projectInfo[0],
|
||||
targetFramework: projectInfo[1],
|
||||
appOutput: projectInfo[2]
|
||||
};
|
||||
|
||||
return projectProperties;
|
||||
}
|
||||
|
||||
private async acquireDebuggers(platformOS: PlatformOS): Promise<void> {
|
||||
await window.withProgress(
|
||||
{
|
||||
|
@ -257,14 +285,6 @@ export class NetCoreDebugHelper implements DebugHelper {
|
|||
return additionalProbingPaths.map(probingPath => `--additionalProbingPath ${probingPath}`).join(' ');
|
||||
}
|
||||
|
||||
private static getContainerAppOutput(debugConfiguration: DockerDebugConfiguration, appOutput: string, platformOS: PlatformOS): string {
|
||||
const result = platformOS === 'Windows' ?
|
||||
path.win32.join('C:\\app', appOutput) :
|
||||
path.posix.join('/app', appOutput);
|
||||
|
||||
return pathNormalize(result, platformOS);
|
||||
}
|
||||
|
||||
private async copyDebuggerToContainer(context: IActionContext, containerName: string, containerDebuggerDirectory: string, containerOS: ContainerOS): Promise<void> {
|
||||
if (containerOS === 'windows') {
|
||||
const inspectInfo = (await ext.runWithDefaults(client =>
|
||||
|
|
|
@ -106,6 +106,7 @@ import { withContainerPathArg } from './withContainerPathArg';
|
|||
import { withDockerAddHostArg } from './withDockerAddHostArg';
|
||||
import { withDockerBuildArg } from './withDockerBuildArg';
|
||||
import { withDockerEnvArg } from './withDockerEnvArg';
|
||||
import { withDockerExposePortsArg } from './withDockerExposePortsArg';
|
||||
import { withDockerBooleanFilterArg, withDockerFilterArg } from './withDockerFilterArg';
|
||||
import { withDockerIgnoreSizeArg } from './withDockerIgnoreSizeArg';
|
||||
import { withDockerJsonFormatArg } from "./withDockerJsonFormatArg";
|
||||
|
@ -683,6 +684,7 @@ export abstract class DockerClientBase extends ConfigurableClient implements ICo
|
|||
withDockerEnvArg(options.environmentVariables),
|
||||
withNamedArg('--env-file', options.environmentFiles),
|
||||
withNamedArg('--entrypoint', options.entrypoint),
|
||||
withDockerExposePortsArg(options.exposePorts),
|
||||
withVerbatimArg(options.customOptions),
|
||||
withArg(options.imageRef),
|
||||
typeof options.command === 'string' ? withVerbatimArg(options.command) : withArg(...(toArray(options.command || []))),
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { withNamedArg } from "../../utils/commandLineBuilder";
|
||||
|
||||
export function withDockerExposePortsArg(ports?: Array<number>) {
|
||||
return withNamedArg('--expose', (ports || []).map(port => port.toString()), { shouldQuote: false });
|
||||
}
|
|
@ -18,7 +18,7 @@ export function formatDockerPlatform(platform: ContainerPlatform): string | unde
|
|||
return `${os}/${architecture}`;
|
||||
}
|
||||
|
||||
/**p
|
||||
/**
|
||||
* This method formats the `platform` flag for the Docker CLI.
|
||||
*
|
||||
* The `os` and `architecture` properties are extracted and used to create a new `ContainerPlatform`
|
||||
|
|
|
@ -744,6 +744,10 @@ export type RunContainerCommandOptions = CommonCommandOptions & {
|
|||
* Optional command to use in starting the container
|
||||
*/
|
||||
command?: Array<string> | string;
|
||||
/**
|
||||
* Optional expose ports for the container
|
||||
*/
|
||||
exposePorts?: Array<number>;
|
||||
/**
|
||||
* Additional custom options to pass
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzureWizard, AzureWizardPromptStep, UserCancelledError } from '@microsoft/vscode-azext-utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { ScaffoldingWizardContext } from '../ScaffoldingWizardContext';
|
||||
import { NetContainerBuildOption, NetSdkChooseBuildStep } from './NetSdkChooseBuildStep';
|
||||
|
||||
export interface NetChooseBuildTypeContext extends ScaffoldingWizardContext {
|
||||
containerBuildOption?: NetContainerBuildOption;
|
||||
}
|
||||
|
||||
export async function netContainerBuild(wizardContext: Partial<NetChooseBuildTypeContext>, apiInput?: NetChooseBuildTypeContext): Promise<void> {
|
||||
if (!vscode.workspace.isTrusted) {
|
||||
throw new UserCancelledError('enforceTrust');
|
||||
}
|
||||
|
||||
const promptSteps: AzureWizardPromptStep<NetChooseBuildTypeContext>[] = [
|
||||
new NetSdkChooseBuildStep()
|
||||
];
|
||||
|
||||
const wizard = new AzureWizard<NetChooseBuildTypeContext>(wizardContext as NetChooseBuildTypeContext, {
|
||||
promptSteps: promptSteps,
|
||||
title: vscode.l10n.t('Initialize for Debugging'),
|
||||
});
|
||||
|
||||
await wizard.prompt();
|
||||
await wizard.execute();
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAzureQuickPickItem } from '@microsoft/vscode-azext-utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { ext } from '../../../extensionVariables';
|
||||
import { TelemetryPromptStep } from '../TelemetryPromptStep';
|
||||
import { cSharpExtensionId, getMinimumCSharpExtensionExports } from '../netCore/netCoreStepUtils';
|
||||
import { NetChooseBuildTypeContext } from './NetContainerBuild';
|
||||
|
||||
/** Key to .NET Container Build Options workplace momento storage */
|
||||
export const NetContainerBuildOptionsKey = 'netContainerBuildOptions';
|
||||
|
||||
export const AllNetContainerBuildOptions = [
|
||||
vscode.l10n.t('Use a Dockerfile'),
|
||||
vscode.l10n.t('Use .NET SDK')
|
||||
] as const;
|
||||
|
||||
type NetContainerBuildOptionsTuple = typeof AllNetContainerBuildOptions;
|
||||
export type NetContainerBuildOption = NetContainerBuildOptionsTuple[number];
|
||||
|
||||
export class NetSdkChooseBuildStep extends TelemetryPromptStep<NetChooseBuildTypeContext> {
|
||||
public async prompt(wizardContext: NetChooseBuildTypeContext): Promise<void> {
|
||||
await this.ensureCSharpExtension(wizardContext);
|
||||
|
||||
// get workspace momento storage
|
||||
const containerBuildOption = await ext.context.workspaceState.get<NetContainerBuildOption>(NetContainerBuildOptionsKey);
|
||||
|
||||
// only remember if it was 'Use .NET SDK', otherwise prompt again
|
||||
if (containerBuildOption === AllNetContainerBuildOptions[1]) {
|
||||
wizardContext.containerBuildOption = containerBuildOption;
|
||||
return;
|
||||
}
|
||||
|
||||
const opt: vscode.QuickPickOptions = {
|
||||
matchOnDescription: true,
|
||||
matchOnDetail: true,
|
||||
placeHolder: vscode.l10n.t('How would you like to build your container image?'),
|
||||
};
|
||||
|
||||
const buildOptions = AllNetContainerBuildOptions as readonly NetContainerBuildOption[];
|
||||
const items = buildOptions.map(p => <IAzureQuickPickItem<NetContainerBuildOption>>{ label: p, data: p });
|
||||
|
||||
const response = await wizardContext.ui.showQuickPick(items, opt);
|
||||
wizardContext.containerBuildOption = response.data;
|
||||
|
||||
// update workspace momento storage
|
||||
await ext.context.workspaceState.update(NetContainerBuildOptionsKey, wizardContext.containerBuildOption);
|
||||
}
|
||||
|
||||
public shouldPrompt(wizardContext: NetChooseBuildTypeContext): boolean {
|
||||
return !wizardContext.containerBuildOption;
|
||||
}
|
||||
|
||||
protected setTelemetry(wizardContext: NetChooseBuildTypeContext): void {
|
||||
wizardContext.telemetry.properties.netSdkBuildStep = wizardContext.containerBuildOption;
|
||||
}
|
||||
|
||||
private async ensureCSharpExtension(wizardContext: NetChooseBuildTypeContext): Promise<void> {
|
||||
try {
|
||||
await getMinimumCSharpExtensionExports();
|
||||
} catch (err) {
|
||||
// Suppress report issue and rethrow
|
||||
wizardContext.errorHandling.suppressReportIssue = true;
|
||||
wizardContext.errorHandling.buttons = [
|
||||
{
|
||||
title: vscode.l10n.t('Open Extension'),
|
||||
callback: async () => vscode.commands.executeCommand('extension.open', cSharpExtensionId),
|
||||
}
|
||||
];
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,22 +11,15 @@ import { getValidImageNameFromPath } from '../../../utils/getValidImageName';
|
|||
import { getNetCoreProjectInfo } from '../../../utils/netCoreUtils';
|
||||
import { GatherInformationStep } from '../GatherInformationStep';
|
||||
import { NetCoreScaffoldingWizardContext } from './NetCoreScaffoldingWizardContext';
|
||||
|
||||
// 1.23.9 contains the fix to not overwrite existing assets
|
||||
const minCSharpVersionString = '1.23.9';
|
||||
import { CSharpExtensionExports, cSharpExtensionId, getMinimumCSharpExtensionExports } from './netCoreStepUtils';
|
||||
|
||||
// All supported .NET versions no longer have "core" in the name
|
||||
const aspNetBaseImage = 'mcr.microsoft.com/dotnet/aspnet';
|
||||
const consoleNetBaseImage = 'mcr.microsoft.com/dotnet/runtime';
|
||||
const netSdkImage = 'mcr.microsoft.com/dotnet/sdk';
|
||||
|
||||
const cSharpExtensionId = 'ms-dotnettools.csharp';
|
||||
const cSharpConfigId = 'csharp';
|
||||
const cSharpPromptSetting = 'suppressBuildAssetsNotification';
|
||||
interface CSharpExtensionExports {
|
||||
// This is a subset of the C# extension's exports but contains all we care about
|
||||
initializationFinished(): Promise<void>;
|
||||
}
|
||||
|
||||
export class NetCoreGatherInformationStep extends GatherInformationStep<NetCoreScaffoldingWizardContext> {
|
||||
private targetFramework: string;
|
||||
|
@ -103,7 +96,7 @@ export class NetCoreGatherInformationStep extends GatherInformationStep<NetCoreS
|
|||
private async ensureNetCoreBuildTasks(wizardContext: NetCoreScaffoldingWizardContext): Promise<void> {
|
||||
let cSharpExtensionExports: CSharpExtensionExports;
|
||||
try {
|
||||
cSharpExtensionExports = await this.getMinimumCSharpExtensionExports();
|
||||
cSharpExtensionExports = await getMinimumCSharpExtensionExports();
|
||||
} catch (err) {
|
||||
// Suppress report issue and rethrow
|
||||
wizardContext.errorHandling.suppressReportIssue = true;
|
||||
|
@ -150,17 +143,4 @@ export class NetCoreGatherInformationStep extends GatherInformationStep<NetCoreS
|
|||
await cSharpPromptConfig.update(cSharpPromptSetting, oldSuppressSettings.globalValue, vscode.ConfigurationTarget.Global);
|
||||
}
|
||||
}
|
||||
|
||||
private async getMinimumCSharpExtensionExports(): Promise<CSharpExtensionExports> {
|
||||
const cSharpExtension: vscode.Extension<CSharpExtensionExports> | undefined = vscode.extensions.getExtension(cSharpExtensionId);
|
||||
const cSharpExtensionVersion: semver.SemVer | undefined = cSharpExtension ? new semver.SemVer((<{ version: string }>cSharpExtension.packageJSON).version) : undefined;
|
||||
|
||||
if (!cSharpExtension || !cSharpExtensionVersion) {
|
||||
throw new Error(vscode.l10n.t('Cannot generate Dockerfiles for a .NET project unless the C# extension is installed.'));
|
||||
} else if (semver.lt(cSharpExtensionVersion, minCSharpVersionString)) {
|
||||
throw new Error(vscode.l10n.t('Cannot generate Dockerfiles for a .NET project unless version {0} or higher of the C# extension is installed.', minCSharpVersionString));
|
||||
}
|
||||
|
||||
return await cSharpExtension.activate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as semver from 'semver';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
// 1.23.9 contains the fix to not overwrite existing assets
|
||||
export const minCSharpVersionString = '1.23.9';
|
||||
export const cSharpExtensionId = 'ms-dotnettools.csharp';
|
||||
|
||||
export interface CSharpExtensionExports {
|
||||
// This is a subset of the C# extension's exports but contains all we care about
|
||||
initializationFinished(): Promise<void>;
|
||||
}
|
||||
|
||||
export async function getMinimumCSharpExtensionExports(): Promise<CSharpExtensionExports> {
|
||||
const cSharpExtension: vscode.Extension<CSharpExtensionExports> | undefined = vscode.extensions.getExtension(cSharpExtensionId);
|
||||
const cSharpExtensionVersion: semver.SemVer | undefined = cSharpExtension ? new semver.SemVer((<{ version: string }>cSharpExtension.packageJSON).version) : undefined;
|
||||
|
||||
if (!cSharpExtension || !cSharpExtensionVersion) {
|
||||
throw new Error(vscode.l10n.t('Cannot generate Dockerfiles for a .NET project unless the C# extension is installed.'));
|
||||
} else if (semver.lt(cSharpExtensionVersion, minCSharpVersionString)) {
|
||||
throw new Error(vscode.l10n.t('Cannot generate Dockerfiles for a .NET project unless version {0} or higher of the C# extension is installed.', minCSharpVersionString));
|
||||
}
|
||||
|
||||
return await cSharpExtension.activate();
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { l10n, Task } from 'vscode';
|
||||
import { DockerPlatform } from '../debugging/DockerPlatformHelper';
|
||||
import { DockerPlatform } from '../debugging/DockerDebugPlatformHelper';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { cloneObject } from '../utils/cloneObject';
|
||||
import { resolveVariables } from '../utils/resolveVariables';
|
||||
|
|
|
@ -52,9 +52,9 @@ export class DockerPseudoterminal implements Pseudoterminal {
|
|||
this.closeEmitter.fire(code || 0);
|
||||
}
|
||||
|
||||
public getCommandRunner(options: Omit<ExecuteCommandInTerminalOptions, 'commandResponse'>): <T>(commandResponse: VoidCommandResponse | PromiseCommandResponse<T>) => Promise<T> {
|
||||
public getCommandRunner(options: Omit<ExecuteCommandResponseInTerminalOptions, 'commandResponse'>): <T>(commandResponse: VoidCommandResponse | PromiseCommandResponse<T>) => Promise<T> {
|
||||
return async <T>(commandResponse: VoidCommandResponse | PromiseCommandResponse<T>) => {
|
||||
const output = await this.executeCommandInTerminal({
|
||||
const output = await this.executeCommandResponseInTerminal({
|
||||
...options,
|
||||
commandResponse: commandResponse,
|
||||
});
|
||||
|
@ -96,18 +96,23 @@ export class DockerPseudoterminal implements Pseudoterminal {
|
|||
this.writeEmitter.fire(`\x1b[${color}${message}\x1b[0m`);
|
||||
}
|
||||
|
||||
private async executeCommandInTerminal(options: ExecuteCommandInTerminalOptions): Promise<ExecAsyncOutput> {
|
||||
private async executeCommandResponseInTerminal(options: ExecuteCommandResponseInTerminalOptions): Promise<ExecAsyncOutput> {
|
||||
const quotedArgs = Shell.getShellOrDefault().quote(options.commandResponse.args);
|
||||
const resolvedQuotedArgs = resolveVariables(quotedArgs, options.folder);
|
||||
const commandLine = [options.commandResponse.command, ...resolvedQuotedArgs].join(' ');
|
||||
|
||||
return await this.execAsyncInTerminal(commandLine, options);
|
||||
}
|
||||
|
||||
public async execAsyncInTerminal(command: string, options?: ExecAsyncInTerminalOptions): Promise<ExecAsyncOutput> {
|
||||
|
||||
// Output what we're doing, same style as VSCode does for ShellExecution/ProcessExecution
|
||||
this.write(`> ${commandLine} <\r\n\r\n`, DEFAULTBOLD);
|
||||
this.write(`> ${command} <\r\n\r\n`, DEFAULTBOLD);
|
||||
|
||||
return await execAsync(
|
||||
commandLine,
|
||||
command,
|
||||
{
|
||||
cwd: this.resolvedDefinition.options?.cwd || options.folder.uri.fsPath,
|
||||
cwd: this.resolvedDefinition.options?.cwd || options.cwd || options.folder.uri.fsPath,
|
||||
env: withDockerEnvSettings({ ...process.env, ...this.resolvedDefinition.options?.env }),
|
||||
cancellationToken: options.token,
|
||||
},
|
||||
|
@ -120,10 +125,15 @@ export class DockerPseudoterminal implements Pseudoterminal {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type ExecuteCommandInTerminalOptions = {
|
||||
type ExecuteCommandResponseInTerminalOptions = ExecAsyncInTerminalOptions & {
|
||||
commandResponse: VoidCommandResponse | PromiseCommandResponse<unknown>;
|
||||
};
|
||||
|
||||
type ExecAsyncInTerminalOptions = {
|
||||
folder: WorkspaceFolder;
|
||||
token?: CancellationToken;
|
||||
cwd?: string;
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { l10n, Task } from 'vscode';
|
||||
import { DockerPlatform } from '../debugging/DockerPlatformHelper';
|
||||
import { DockerPlatform } from '../debugging/DockerDebugPlatformHelper';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { RunContainerBindMount } from '../runtimes/docker';
|
||||
import { cloneObject } from '../utils/cloneObject';
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DockerPlatform } from "../debugging/DockerDebugPlatformHelper";
|
||||
import { DockerBuildTaskDefinition } from "./DockerBuildTaskProvider";
|
||||
import { DockerRunTaskDefinition } from "./DockerRunTaskProvider";
|
||||
|
||||
export function getTaskPlatform(definition: DockerBuildTaskDefinition | DockerRunTaskDefinition): DockerPlatform | undefined {
|
||||
if (definition.platform === 'netCore' || definition.netCore !== undefined) {
|
||||
return 'netCore';
|
||||
} else if (definition.platform === 'node' || definition.node !== undefined) {
|
||||
return 'node';
|
||||
} else if (definition.platform === 'python' || definition.python !== undefined) {
|
||||
return 'python';
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -5,12 +5,13 @@
|
|||
|
||||
import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from '@microsoft/vscode-azext-utils';
|
||||
import { CancellationToken, CustomExecution, l10n, ProviderResult, Task, TaskDefinition, TaskProvider } from 'vscode';
|
||||
import { DockerPlatform, getPlatform } from '../debugging/DockerPlatformHelper';
|
||||
import { DockerPlatform } from '../debugging/DockerDebugPlatformHelper';
|
||||
import { ext } from '../extensionVariables';
|
||||
import { ExecError } from '../utils/execAsync';
|
||||
import { DockerBuildTask } from './DockerBuildTaskProvider';
|
||||
import { DockerPseudoterminal } from './DockerPseudoterminal';
|
||||
import { DockerRunTask } from './DockerRunTaskProvider';
|
||||
import { getTaskPlatform } from './DockerTaskPlatformHelper';
|
||||
import { DockerTaskExecutionContext, DockerTaskProviderName, TaskHelper } from './TaskHelper';
|
||||
|
||||
export abstract class DockerTaskProvider implements TaskProvider {
|
||||
|
@ -46,7 +47,7 @@ export abstract class DockerTaskProvider implements TaskProvider {
|
|||
}
|
||||
|
||||
context.actionContext = actionContext;
|
||||
context.platform = getPlatform(task.definition);
|
||||
context.platform = getTaskPlatform(task.definition);
|
||||
|
||||
context.actionContext.telemetry.properties.dockerPlatform = context.platform;
|
||||
await this.executeTaskInternal(context, task);
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as path from 'path';
|
|||
import { CancellationToken, ConfigurationTarget, ExtensionContext, QuickPickItem, Task, WorkspaceFolder, l10n, tasks, workspace } from 'vscode';
|
||||
import { DebugConfigurationBase } from '../debugging/DockerDebugConfigurationBase';
|
||||
import { DockerDebugConfiguration } from '../debugging/DockerDebugConfigurationProvider';
|
||||
import { DockerPlatform } from '../debugging/DockerPlatformHelper';
|
||||
import { DockerPlatform } from '../debugging/DockerDebugPlatformHelper';
|
||||
import { ContainerPlatform } from '../runtimes/docker';
|
||||
import { getValidImageName, getValidImageNameWithTag } from '../utils/getValidImageName';
|
||||
import { pathNormalize } from '../utils/pathNormalize';
|
||||
|
@ -20,11 +20,12 @@ import { DockerPseudoterminal } from './DockerPseudoterminal';
|
|||
import { DockerContainerVolume, DockerRunOptions, DockerRunTaskDefinitionBase } from './DockerRunTaskDefinitionBase';
|
||||
import { DockerRunTask, DockerRunTaskDefinition, DockerRunTaskProvider } from './DockerRunTaskProvider';
|
||||
import { TaskDefinitionBase } from './TaskDefinitionBase';
|
||||
import { NetSdkRunTaskProvider } from './netSdk/NetSdkRunTaskProvider';
|
||||
import { netCoreTaskHelper } from './netcore/NetCoreTaskHelper';
|
||||
import { nodeTaskHelper } from './node/NodeTaskHelper';
|
||||
import { pythonTaskHelper } from './python/PythonTaskHelper';
|
||||
|
||||
export type DockerTaskProviderName = 'docker-build' | 'docker-run' | 'docker-compose';
|
||||
export type DockerTaskProviderName = 'docker-build' | 'docker-run' | 'docker-compose' | 'dotnet-container-sdk';
|
||||
|
||||
export interface DockerTaskContext {
|
||||
folder: WorkspaceFolder;
|
||||
|
@ -77,7 +78,8 @@ export function registerTaskProviders(ctx: ExtensionContext): void {
|
|||
const helpers = {
|
||||
netCore: netCoreTaskHelper,
|
||||
node: nodeTaskHelper,
|
||||
python: pythonTaskHelper
|
||||
python: pythonTaskHelper,
|
||||
netSdk: undefined
|
||||
};
|
||||
|
||||
ctx.subscriptions.push(
|
||||
|
@ -100,6 +102,13 @@ export function registerTaskProviders(ctx: ExtensionContext): void {
|
|||
new DockerComposeTaskProvider()
|
||||
)
|
||||
);
|
||||
|
||||
ctx.subscriptions.push(
|
||||
tasks.registerTaskProvider(
|
||||
'dotnet-container-sdk',
|
||||
new NetSdkRunTaskProvider()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function hasTask(taskLabel: string, folder: WorkspaceFolder): boolean {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from "path";
|
||||
import { CancellationToken, CustomExecution, Task, TaskDefinition, TaskScope } from "vscode";
|
||||
import { DockerPseudoterminal } from "../DockerPseudoterminal";
|
||||
import { DockerRunTask } from "../DockerRunTaskProvider";
|
||||
import { DockerTaskProvider } from '../DockerTaskProvider';
|
||||
import { DockerRunTaskContext } from '../TaskHelper';
|
||||
import { NetCoreRunTaskDefinition, NetCoreTaskHelper } from "../netcore/NetCoreTaskHelper";
|
||||
import { NetSdkRunTaskType, getNetSdkBuildCommand, getNetSdkRunCommand } from './netSdkTaskUtils';
|
||||
|
||||
const NetSdkDebugTaskName = 'debug';
|
||||
|
||||
export type NetSdkRunTaskDefinition = NetCoreRunTaskDefinition;
|
||||
|
||||
export class NetSdkRunTaskProvider extends DockerTaskProvider {
|
||||
|
||||
public constructor() { super(NetSdkRunTaskType, undefined); }
|
||||
|
||||
public provideTasks(token: CancellationToken): Task[] {
|
||||
return []; // this task is not discoverable this way
|
||||
}
|
||||
|
||||
protected async executeTaskInternal(context: DockerRunTaskContext, task: DockerRunTask): Promise<void> {
|
||||
const projectPath = task.definition.netCore?.appProject;
|
||||
const isProjectWebApp = await NetCoreTaskHelper.isWebApp(projectPath);
|
||||
const projectFolderPath = path.dirname(projectPath);
|
||||
|
||||
// use dotnet to build the image
|
||||
const buildCommand = await getNetSdkBuildCommand(isProjectWebApp, task.definition.dockerRun.image);
|
||||
await context.terminal.execAsyncInTerminal(
|
||||
buildCommand,
|
||||
{
|
||||
folder: context.folder,
|
||||
token: context.cancellationToken,
|
||||
cwd: projectFolderPath,
|
||||
}
|
||||
);
|
||||
|
||||
// use docker run to run the image
|
||||
const runCommand = await getNetSdkRunCommand(isProjectWebApp, task.definition.dockerRun.image);
|
||||
await context.terminal.execAsyncInTerminal(
|
||||
runCommand,
|
||||
{
|
||||
folder: context.folder,
|
||||
token: context.cancellationToken,
|
||||
cwd: projectFolderPath,
|
||||
}
|
||||
);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public createNetSdkRunTask(options?: Omit<NetSdkRunTaskDefinition, "type">): { task: Task, promise: Promise<number> } {
|
||||
let task: Task;
|
||||
const definition = {
|
||||
...options,
|
||||
type: NetSdkRunTaskType,
|
||||
};
|
||||
|
||||
const promise = new Promise<number>((resolve, reject) => {
|
||||
task = new Task(
|
||||
definition,
|
||||
TaskScope.Workspace,
|
||||
NetSdkDebugTaskName,
|
||||
NetSdkRunTaskType,
|
||||
new CustomExecution(async (resolveDefinition: TaskDefinition) => {
|
||||
const pseudoTerminal = new DockerPseudoterminal(new NetSdkRunTaskProvider(), task, resolveDefinition);
|
||||
|
||||
const closeEventRegistration = pseudoTerminal.onDidClose((exitCode: number) => {
|
||||
closeEventRegistration.dispose();
|
||||
|
||||
if (exitCode === 0) {
|
||||
resolve(exitCode);
|
||||
} else {
|
||||
reject(exitCode);
|
||||
}
|
||||
});
|
||||
|
||||
return pseudoTerminal;
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
return { task, promise };
|
||||
}
|
||||
}
|
||||
|
||||
export const netSdkRunTaskProvider = new NetSdkRunTaskProvider();
|
|
@ -0,0 +1,116 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import { vsDbgInstallBasePath } from "../../debugging/netcore/VsDbgHelper";
|
||||
import { ext } from "../../extensionVariables";
|
||||
import { RunContainerBindMount, RunContainerCommandOptions, Shell, composeArgs, withArg, withNamedArg } from "../../runtimes/docker";
|
||||
import { getImageNameWithTag } from '../../utils/getValidImageName';
|
||||
import { getDockerOSType } from "../../utils/osUtils";
|
||||
import { defaultVsCodeLabels } from "../TaskDefinitionBase";
|
||||
import { getDefaultContainerName } from '../TaskHelper';
|
||||
|
||||
/**
|
||||
* Native architecture of the current machine in the RID format
|
||||
* {@link https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json}
|
||||
*/
|
||||
export type RidCpuArchitecture =
|
||||
| 'x64'
|
||||
| 'x86'
|
||||
| 'arm64'
|
||||
| 'arm'
|
||||
| 'ppc64le'
|
||||
| 'mips64'
|
||||
| 's390x'
|
||||
| string;
|
||||
|
||||
export const NetSdkRunTaskType = 'dotnet-container-sdk';
|
||||
const NetSdkDefaultImageTag = 'dev'; // intentionally default to dev tag for phase 1 of this feature
|
||||
|
||||
export async function getNetSdkBuildCommand(isProjectWebApp: boolean, imageName: string): Promise<string> {
|
||||
const configuration = 'Debug'; // intentionally default to Debug configuration for phase 1 of this feature
|
||||
|
||||
// {@link https://github.com/dotnet/sdk-container-builds/issues/141} this could change in the future
|
||||
const publishFlag = isProjectWebApp
|
||||
? '-p:PublishProfile=DefaultContainer'
|
||||
: '/t:PublishContainer';
|
||||
|
||||
const args = composeArgs(
|
||||
withArg('dotnet', 'publish'),
|
||||
withNamedArg('--os', await normalizeOsToRidOs()),
|
||||
withNamedArg('--arch', await normalizeArchitectureToRidArchitecture()),
|
||||
withArg(publishFlag),
|
||||
withNamedArg('--configuration', configuration),
|
||||
withNamedArg('-p:ContainerImageTag', NetSdkDefaultImageTag, { assignValue: true })
|
||||
)();
|
||||
|
||||
const quotedArgs = Shell.getShellOrDefault().quote(args);
|
||||
return quotedArgs.join(' ');
|
||||
}
|
||||
|
||||
export async function getNetSdkRunCommand(isProjectWebApp: boolean, imageName: string): Promise<string> {
|
||||
const client = await ext.runtimeManager.getClient();
|
||||
|
||||
const options: RunContainerCommandOptions = {
|
||||
detached: true,
|
||||
publishAllPorts: true,
|
||||
name: getDefaultContainerName(imageName, NetSdkDefaultImageTag),
|
||||
environmentVariables: {},
|
||||
removeOnExit: true,
|
||||
imageRef: getImageNameWithTag(imageName, NetSdkDefaultImageTag),
|
||||
labels: defaultVsCodeLabels,
|
||||
mounts: await getRemoteDebuggerMount(),
|
||||
entrypoint: await getDockerOSType() === 'windows' ? 'cmd.exe' : '/bin/sh'
|
||||
};
|
||||
|
||||
if (isProjectWebApp) {
|
||||
options.exposePorts = [8080, 80]; // the default port is 8080 for .NET 8 and 80 for .NET 7
|
||||
}
|
||||
|
||||
const command = await client.runContainer(options);
|
||||
const quotedArgs = Shell.getShellOrDefault().quote(command.args);
|
||||
const commandLine = [client.commandName, ...quotedArgs].join(' ');
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method normalizes the Docker OS type to match the .NET Core SDK conventions.
|
||||
* {@link https://learn.microsoft.com/en-us/dotnet/core/rid-catalog}
|
||||
*/
|
||||
export async function normalizeOsToRidOs(): Promise<'linux' | 'win'> {
|
||||
const dockerOsType = await getDockerOSType();
|
||||
return dockerOsType === 'windows' ? 'win' : 'linux';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method normalizes the native architecture to match the .NET Core SDK conventions.
|
||||
* {@link https://learn.microsoft.com/en-us/dotnet/core/rid-catalog}
|
||||
*/
|
||||
export async function normalizeArchitectureToRidArchitecture(): Promise<RidCpuArchitecture> {
|
||||
const architecture = os.arch();
|
||||
switch (architecture) {
|
||||
case 'x32':
|
||||
case 'ia32':
|
||||
return 'x86';
|
||||
default:
|
||||
return architecture;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods returns the mount for the remote debugger ONLY as the SDK built container will have
|
||||
* everything it needs to run the app already inside.
|
||||
*/
|
||||
async function getRemoteDebuggerMount(): Promise<RunContainerBindMount[] | undefined> {
|
||||
const debuggerVolume: RunContainerBindMount = {
|
||||
type: 'bind',
|
||||
source: vsDbgInstallBasePath,
|
||||
destination: await getDockerOSType() === 'windows' ? 'C:\\remote_debugger' : '/remote_debugger',
|
||||
readOnly: true
|
||||
};
|
||||
return [debuggerVolume];
|
||||
}
|
||||
|
||||
|
|
@ -4,22 +4,22 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtParentTreeItem, AzExtTreeItem, AzureWizard, GenericTreeItem, IActionContext, parseError } from "@microsoft/vscode-azext-utils";
|
||||
import { ConfigurationTarget, l10n, ThemeColor, ThemeIcon, workspace, WorkspaceConfiguration } from "vscode";
|
||||
import { showDockerInstallNotification } from "../commands/dockerInstaller";
|
||||
import { ConfigurationTarget, ThemeColor, ThemeIcon, WorkspaceConfiguration, l10n, workspace } from "vscode";
|
||||
import { showDockerLearnMoreNotification } from "../commands/showDockerLearnMoreNotification";
|
||||
import { configPrefix } from "../constants";
|
||||
import { ext } from "../extensionVariables";
|
||||
import { isCommandNotSupportedError, ListContainersItem, ListContextItem, ListImagesItem, ListNetworkItem, ListVolumeItem } from "../runtimes/docker";
|
||||
import { DockerExtensionKind, getVSCodeRemoteInfo, IVSCodeRemoteInfo, RemoteKind } from "../utils/getVSCodeRemoteInfo";
|
||||
import { ListContainersItem, ListContextItem, ListImagesItem, ListNetworkItem, ListVolumeItem, isCommandNotSupportedError } from "../runtimes/docker";
|
||||
import { runtimeInstallStatusProvider } from "../utils/RuntimeInstallStatusProvider";
|
||||
import { DatedDockerImage } from "./images/ImagesTreeItem";
|
||||
import { DockerExtensionKind, IVSCodeRemoteInfo, RemoteKind, getVSCodeRemoteInfo } from "../utils/getVSCodeRemoteInfo";
|
||||
import { LocalGroupTreeItemBase } from "./LocalGroupTreeItemBase";
|
||||
import { OpenUrlTreeItem } from "./OpenUrlTreeItem";
|
||||
import { TreePrefix } from "./TreePrefix";
|
||||
import { DatedDockerImage } from "./images/ImagesTreeItem";
|
||||
import { CommonGroupBy, CommonProperty, CommonSortBy, sortByProperties } from "./settings/CommonProperties";
|
||||
import { ITreeArraySettingInfo, ITreeSettingInfo } from "./settings/ITreeSettingInfo";
|
||||
import { ITreeSettingsWizardContext, ITreeSettingWizardInfo } from "./settings/ITreeSettingsWizardContext";
|
||||
import { ITreeSettingWizardInfo, ITreeSettingsWizardContext } from "./settings/ITreeSettingsWizardContext";
|
||||
import { TreeSettingListStep } from "./settings/TreeSettingListStep";
|
||||
import { TreeSettingStep } from "./settings/TreeSettingStep";
|
||||
import { TreePrefix } from "./TreePrefix";
|
||||
|
||||
type DockerStatus = 'NotInstalled' | 'Installed' | 'Running';
|
||||
|
||||
|
@ -323,7 +323,7 @@ export abstract class LocalRootTreeItemBase<TItem extends AnyContainerObject, TP
|
|||
if (!dockerInstallNotificationShownToUser && this._currentDockerStatus === 'NotInstalled') {
|
||||
dockerInstallNotificationShownToUser = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
showDockerInstallNotification();
|
||||
showDockerLearnMoreNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AzExtParentTreeItem, AzExtTreeItem, GenericTreeItem, IActionContext } from "@microsoft/vscode-azext-utils";
|
||||
import { l10n, ThemeIcon } from "vscode";
|
||||
import { getThemedIconPath } from '../getThemedIconPath';
|
||||
import { ThemeIcon, l10n } from "vscode";
|
||||
import { OpenUrlTreeItem } from "../OpenUrlTreeItem";
|
||||
|
||||
export class HelpsTreeItem extends AzExtParentTreeItem {
|
||||
|
@ -21,7 +20,7 @@ export class HelpsTreeItem extends AzExtParentTreeItem {
|
|||
this.openWalkthroughTreeItem,
|
||||
this.reviewIssuesTreeItem,
|
||||
this.reportIssuesTreeItem,
|
||||
this.installDockerTreeItem,
|
||||
this.learnMoreDownloadDockerTreeItem,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -115,14 +114,14 @@ export class HelpsTreeItem extends AzExtParentTreeItem {
|
|||
return node;
|
||||
}
|
||||
|
||||
private get installDockerTreeItem(): AzExtTreeItem {
|
||||
private get learnMoreDownloadDockerTreeItem(): AzExtTreeItem {
|
||||
const node = new GenericTreeItem(
|
||||
this,
|
||||
{
|
||||
label: l10n.t('Install Docker'),
|
||||
contextValue: 'Install Docker',
|
||||
commandId: 'vscode-docker.installDocker',
|
||||
iconPath: getThemedIconPath('docker'),
|
||||
label: l10n.t('Docker Installation'),
|
||||
contextValue: 'Docker Installation',
|
||||
commandId: 'vscode-docker.openDockerDownloadPage',
|
||||
iconPath: new ThemeIcon('link-external'),
|
||||
includeInTreeItemPicker: true,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -13,7 +13,7 @@ export async function resolveTooltipMarkdown(templateString: string, context: un
|
|||
|
||||
const markdownString = template(context);
|
||||
const result = new MarkdownString(markdownString, true);
|
||||
result.isTrusted = true;
|
||||
result.isTrusted = { enabledCommands: ['revealFileInOS'] }; // revealFileInOS is used in container tooltips
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
import * as cp from 'child_process';
|
||||
import * as stream from 'stream';
|
||||
import { AccumulatorStream, Shell, spawnStreamAsync, StreamSpawnOptions } from '../runtimes/docker';
|
||||
import { CancellationToken } from 'vscode';
|
||||
import { AccumulatorStream, Shell, spawnStreamAsync, StreamSpawnOptions } from '../runtimes/docker';
|
||||
|
||||
type Progress = (content: string, err: boolean) => void;
|
||||
|
||||
|
|
|
@ -16,5 +16,9 @@ export function getValidImageNameFromPath(appPath: string, tag?: string): string
|
|||
}
|
||||
|
||||
export function getValidImageNameWithTag(nameHint: string, tag: string): string {
|
||||
return `${getValidImageName(nameHint)}:${tag}`;
|
||||
return getImageNameWithTag(getValidImageName(nameHint), tag);
|
||||
}
|
||||
|
||||
export function getImageNameWithTag(name: string, tag: string): string {
|
||||
return `${name}:${tag}`;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ import { ext } from '../extensionVariables';
|
|||
import { execAsync } from './execAsync';
|
||||
import { getTempFileName } from './osUtils';
|
||||
|
||||
export async function getNetCoreProjectInfo(target: 'GetBlazorManifestLocations' | 'GetProjectProperties', project: string): Promise<string[]> {
|
||||
export async function getNetCoreProjectInfo(target: 'GetBlazorManifestLocations' | 'GetProjectProperties', project: string, additionalProperties?: string): Promise<string[]> {
|
||||
const targetsFile = path.join(ext.context.asAbsolutePath('resources'), 'netCore', `${target}.targets`);
|
||||
const outputFile = getTempFileName();
|
||||
|
||||
const command = `dotnet build /r:false /t:${target} /p:CustomAfterMicrosoftCommonTargets="${targetsFile}" /p:CustomAfterMicrosoftCommonCrossTargetingTargets="${targetsFile}" /p:InfoOutputPath="${outputFile}" "${project}"`;
|
||||
const command = `dotnet build /r:false /t:${target} /p:CustomAfterMicrosoftCommonTargets="${targetsFile}" /p:CustomAfterMicrosoftCommonCrossTargetingTargets="${targetsFile}" /p:InfoOutputPath="${outputFile}" ${additionalProperties || ''} "${project}"`;
|
||||
|
||||
try {
|
||||
try {
|
||||
|
|
Загрузка…
Ссылка в новой задаче