Revert "Add deploySteps and variables to cppdbg (#9418)"

This reverts commit b55a98c697.
This commit is contained in:
Sean McManus 2022-07-08 11:05:16 -07:00
Родитель 2a39dc402a
Коммит e2ca8e8455
17 изменённых файлов: 87 добавлений и 2681 удалений

1
Extension/.gitignore поставляемый
Просмотреть файл

@ -33,4 +33,3 @@ localized_string_ids.h
# ignore generate files. It will be generated when building
src/nativeStrings.ts
vscode*.d.ts

Просмотреть файл

@ -1,8 +1,11 @@
# C/C++ for Visual Studio Code Change Log
## Version 1.11.2 (pre-release): July 8, 2022
### Enhancements
* Add deploySteps and variables to cppdbg. [PR #9418](https://github.com/microsoft/vscode-cpptools/pull/9418)
## Version 1.11.1 (pre-release): July 7, 2022
### Enhancements
* Add deploySteps and variables to cppdbg. [PR #9418](https://github.com/microsoft/vscode-cpptools/pull/9418)
* Move "auto" inlay hints to the right by default and add `C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft`. [#9478](https://github.com/microsoft/vscode-cpptools/issues/9478)
* Allow breakpoints for Rust debugging. [PR #9484](https://github.com/microsoft/vscode-cpptools/pull/9484)
* Remove `_` from the start of parameter inlay hints and add `C_Cpp.inlayHints.parameterNames.hideLeadingUnderscores`. [#9485](https://github.com/microsoft/vscode-cpptools/issues/9485)

Просмотреть файл

@ -2,7 +2,7 @@
"name": "cpptools",
"displayName": "C/C++",
"description": "C/C++ IntelliSense, debugging, and code browsing.",
"version": "1.11.1-main",
"version": "1.11.2-main",
"publisher": "ms-vscode",
"icon": "LanguageCCPP_color_128x.png",
"readme": "README.md",
@ -37,9 +37,6 @@
"Linters",
"Snippets"
],
"enabledApiProposals": [
"terminalDataWriteEvent"
],
"capabilities": {
"untrustedWorkspaces": {
"supported": false,
@ -420,34 +417,34 @@
"scope": "resource"
},
"C_Cpp.codeAnalysis.clangTidy.codeAction.showClear": {
"type": "string",
"description": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description%",
"enum": [
"None",
"AllOnly",
"AllAndAllType",
"AllAndAllTypeAndThis"
],
"enumDescriptions": [
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.None.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description%"
],
"default": "AllAndAllTypeAndThis",
"scope": "application"
"type": "string",
"description": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description%",
"enum": [
"None",
"AllOnly",
"AllAndAllType",
"AllAndAllTypeAndThis"
],
"enumDescriptions": [
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.None.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description%",
"%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description%"
],
"default": "AllAndAllTypeAndThis",
"scope": "application"
},
"C_Cpp.codeAnalysis.clangTidy.codeAction.showDisable": {
"type": "boolean",
"markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription%",
"default": true,
"scope": "application"
"type": "boolean",
"markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription%",
"default": true,
"scope": "application"
},
"C_Cpp.codeAnalysis.clangTidy.codeAction.showDocumentation": {
"type": "boolean",
"markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription%",
"default": true,
"scope": "application"
"type": "boolean",
"markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription%",
"default": true,
"scope": "application"
},
"C_Cpp.codeAnalysis.runAutomatically": {
"type": "boolean",
@ -3299,427 +3296,6 @@
"default": 0
}
}
},
"variables": {
"type": "object",
"description": "%c_cpp.debuggers.variables.description%",
"default": {
"<variable-name>": "<variable-value>"
},
"properties": {},
"additionalProperties": {
"type": "string",
"description": "%c_cpp.debuggers.variables.properties.description%",
"default": ""
}
},
"deploySteps": {
"type": "array",
"description": "%c_cpp.debuggers.deploySteps.description%",
"items": {
"anyOf": [
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": {},
"required": [
"type",
"files",
"host",
"targetDir"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": "",
"enum": [
"scp"
]
},
"files": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "%c_cpp.debuggers.deploySteps.scp.files.description%",
"default": ""
},
"host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"targetDir": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.targetDir.description%",
"default": ""
},
"scpPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.scpPath.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": {},
"required": [
"type",
"host",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": "",
"enum": [
"ssh"
]
},
"host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.command.description%",
"default": ""
},
"sshPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.sshPath.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": "",
"enum": [
"shell"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.command.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": "",
"enum": [
"command"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.command.description%",
"default": ""
},
"args": {
"type": "array",
"description": "%c_cpp.debuggers.vsCodeCommand.args.description%",
"items": {
"type": "string"
}
}
}
}
]
},
"default": []
}
}
},
@ -3974,427 +3550,6 @@
"default": ""
}
}
},
"variables": {
"type": "object",
"description": "%c_cpp.debuggers.variables.description%",
"default": {
"<variable-name>": "<variable-value>"
},
"properties": {},
"additionalProperties": {
"type": "string",
"description": "%c_cpp.debuggers.variables.properties.description%",
"default": ""
}
},
"deploySteps": {
"type": "array",
"description": "%c_cpp.debuggers.deploySteps.description%",
"items": {
"anyOf": [
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": {},
"required": [
"type",
"files",
"host",
"targetDir"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": "",
"enum": [
"scp"
]
},
"files": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "%c_cpp.debuggers.deploySteps.scp.files.description%",
"default": ""
},
"host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"targetDir": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.targetDir.description%",
"default": ""
},
"scpPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.scpPath.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": {},
"required": [
"type",
"host",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": "",
"enum": [
"ssh"
]
},
"host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.command.description%",
"default": ""
},
"sshPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.sshPath.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": "",
"enum": [
"shell"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.command.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": "",
"enum": [
"command"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.command.description%",
"default": ""
},
"args": {
"type": "array",
"description": "%c_cpp.debuggers.vsCodeCommand.args.description%",
"items": {
"type": "string"
}
}
}
}
]
},
"default": []
}
}
}
@ -5361,14 +4516,10 @@
"unitTests": "tsc -p test.tsconfig.json && node ./out/test/unitTests/runTest.js",
"integrationTests": "tsc -p test.tsconfig.json && node ./out/test/integrationTests/languageServer/runTest.js",
"intelliSenseFeaturesTests": "tsc -p test.tsconfig.json && node ./out/test/integrationTests/IntelliSenseFeatures/runTest.js",
"import-edge-strings": "node ./import_edge_strings.js",
"download-api": "vscode-dts dev",
"postdownload-api": "vscode-dts master",
"postinstall": "npm run download-api"
"import-edge-strings": "node ./import_edge_strings.js"
},
"devDependencies": {
"@octokit/rest": "^18.12.0",
"@types/glob": "^7.1.3",
"@types/minimatch": "^3.0.3",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^8.2.2",
@ -5376,6 +4527,7 @@
"@types/plist": "^3.0.2",
"@types/semver": "^7.1.0",
"@types/tmp": "^0.1.0",
"@types/vscode": "1.65.0",
"@types/which": "^1.3.2",
"@types/yauzl": "^2.9.1",
"@typescript-eslint/eslint-plugin": "^4.31.1",
@ -5389,6 +4541,7 @@
"eslint-plugin-jsdoc": "^39.3.3",
"event-stream": "^4.0.1",
"fs-extra": "^8.1.0",
"glob": "^7.1.6",
"gulp": "^4.0.2",
"gulp-env": "^0.4.0",
"gulp-eslint": "^6.0.0",
@ -5407,7 +4560,6 @@
"typescript": "^4.4.3",
"vscode-debugadapter": "^1.35.0",
"vscode-debugprotocol": "^1.35.0",
"vscode-dts": "^0.3.2",
"vscode-nls-dev": "^4.0.0-next.1",
"webpack": "^5.28.0",
"webpack-cli": "^4.5.0",
@ -5417,7 +4569,6 @@
"comment-json": "^4.1.1",
"editorconfig": "^0.15.3",
"escape-string-regexp": "^2.0.0",
"glob": "^7.1.6",
"https-proxy-agent": "^2.2.4",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.5",

Просмотреть файл

@ -301,35 +301,6 @@
"c_cpp.debuggers.hardwareBreakpoints.description": "Explicit control of hardware breakpoint behavior for remote targets.",
"c_cpp.debuggers.hardwareBreakpoints.require.description": "If true, always use hardware breakpoints. Defaults to false.",
"c_cpp.debuggers.hardwareBreakpoints.limit.description": "Optional limit on the number of available hardware breakpoints to use. Only enforced when \"require\" is true and \"limit\" is greater than 0. Defaults to 0.",
"c_cpp.debuggers.variables.description": "Variables for recursive substitution in this launch configuration. Each variable may refer to others.",
"c_cpp.debuggers.variables.properties.description": "Variable for recursive substitution in this launch configuration. The value may refer to other variables.",
"c_cpp.debuggers.host.description": "Host information.",
"c_cpp.debuggers.host.user.description": "User logging into the host.",
"c_cpp.debuggers.host.hostName.description": "Host name.",
"c_cpp.debuggers.host.port.description": "SSH port on the host. Default is 22.",
"c_cpp.debuggers.host.jumpHost.description": "Connect to the target host by first making a connection to the jump hosts.",
"c_cpp.debuggers.host.localForward.description": "Forward connections to the given TCP port or Unix socket on the local (client) host to the given host and port, or Unix socket, on the remote side",
"c_cpp.debuggers.host.localForward.bindAddress.description": "Local address",
"c_cpp.debuggers.host.localForward.port.description": "Local port",
"c_cpp.debuggers.host.localForward.host.description": "Host name",
"c_cpp.debuggers.host.localForward.hostPort.description": "Host port",
"c_cpp.debuggers.host.localForward.localSocket.description": "Local socket",
"c_cpp.debuggers.host.localForward.remoteSocket.description": "Remote socket",
"c_cpp.debuggers.deploySteps.description": "Steps needed to deploy the application. Order matters.",
"c_cpp.debuggers.deploySteps.scp.description": "Copy files using SCP.",
"c_cpp.debuggers.deploySteps.scp.files.description": "Files to be copied via SCP. Supports path pattern.",
"c_cpp.debuggers.deploySteps.scp.targetDir.description": "Target directory.",
"c_cpp.debuggers.deploySteps.scp.scpPath.description": "Optional full path to SCP. Assumes SCP is on PATH if not specified",
"c_cpp.debuggers.deploySteps.debug": "If true, skip when starting without debugging. If false, skip when starting debugging. If undefined, never skip.",
"c_cpp.debuggers.deploySteps.ssh.description": "SSH command step.",
"c_cpp.debuggers.deploySteps.ssh.command.description": "Command to be executed via SSH. The command after '-c' in SSH command.",
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Optional full path to SSH. Assumes SSH is on PATH if not specified",
"c_cpp.debuggers.deploySteps.continueOn.description": "An optional finish pattern in output. When this pattern is seen in the output, continue the deploy procedures regardless of whether this step returns.",
"c_cpp.debuggers.deploySteps.shell.description": "Shell command step.",
"c_cpp.debuggers.deploySteps.shell.command.description": "Shell command to be executed.",
"c_cpp.debuggers.vsCodeCommand.description": "VS Code command to be invoked. Can be a command in VS Code or an active extension.",
"c_cpp.debuggers.vsCodeCommand.command.description": "VS Code command to be invoked.",
"c_cpp.debuggers.vsCodeCommand.args.description": "Arguments to the VS Code command.",
"c_cpp.taskDefinitions.name.description": "The name of the task.",
"c_cpp.taskDefinitions.command.description": "The path to either a compiler or script that performs compilation.",
"c_cpp.taskDefinitions.args.description": "Additional arguments to pass to the compiler or compilation script.",

Просмотреть файл

@ -23,24 +23,10 @@ import { PlatformInformation } from '../platform';
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
import { CppSettings, OtherSettings } from '../LanguageServer/settings';
import { configPrefix } from '../LanguageServer/extension';
import { expandAllStrings, ExpansionOptions, ExpansionVars } from '../expand';
import { scp, ssh } from '../SSH/commands';
import * as glob from 'glob';
import { promisify } from 'util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
enum StepType {
scp = 'scp',
ssh = 'ssh',
shell = 'shell',
remoteShell = 'remoteShell',
command = 'command'
}
const globAsync: (pattern: string, options?: glob.IOptions | undefined) => Promise<string[]> = promisify(glob);
/*
* Retrieves configurations from a provider and displays them in a quickpick menu to be selected.
* Ensures that the selected configuration's preLaunchTask (if existent) is populated in the user's task.json.
@ -219,11 +205,11 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
* This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted.
* This is also ran after the tasks.json has completed.
*
* Try to add all missing attributes to the debug configuration being launched.
* Try to add all missing attributes to the debug configuration being launched.
* If return "undefined", the debugging will be aborted silently.
* If return "null", the debugging will be aborted and launch.json will be opened.
*/
async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): Promise<CppDebugConfiguration | null | undefined> {
*/
resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult<CppDebugConfiguration> {
if (!config || !config.type) {
return undefined; // Abort debugging silently.
}
@ -246,7 +232,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Disable debug heap by default, enable if 'enableDebugHeap' is set.
if (!config.enableDebugHeap) {
const disableDebugHeapEnvSetting: Environment = { "name": "_NO_DEBUG_HEAP", "value": "1" };
const disableDebugHeapEnvSetting: Environment = {"name" : "_NO_DEBUG_HEAP", "value" : "1"};
if (config.environment && util.isArray(config.environment)) {
config.environment.push(disableDebugHeapEnvSetting);
@ -259,8 +245,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Add environment variables from .env file
this.resolveEnvFile(config, folder);
await this.expand(config, folder);
this.resolveSourceFileMapVariables(config);
// Modify WSL config for OpenDebugAD7
@ -323,19 +307,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// logger.showOutputChannel();
}
// Run deploy steps
if (config.deploySteps && config.deploySteps.length !== 0) {
const codeVersion: number[] = vscode.version.split('.').map(num => parseInt(num, undefined));
if ((util.isNumber(codeVersion[0]) && codeVersion[0] < 1) || (util.isNumber(codeVersion[0]) && codeVersion[0] === 1 && util.isNumber(codeVersion[1]) && codeVersion[1] < 69)) {
logger.getOutputChannelLogger().showErrorMessage(localize("vs.code.1.69+.required", "'deploySteps' require VS Code 1.69+."));
return undefined;
}
const deploySucceeded: boolean = await this.deploySteps(config, token);
if (!deploySucceeded || token?.isCancellationRequested) {
return undefined;
}
}
return config;
}
@ -624,17 +595,17 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, undefined);
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += (message ? ' ' : '\t');
message += localize("replacing.targetpath", "Replacing {0} '{1}' with '{2}'.", "targetPath", sourceFileMapTarget, newSourceFileMapTarget);
target = newSourceFileMapTarget;
}
} else if (util.isObject(sourceFileMapTarget)) {
const newSourceFileMapTarget: { "editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
const newSourceFileMapTarget: {"editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
newSourceFileMapTarget["editorPath"] = util.resolveVariables(sourceFileMapTarget["editorPath"], undefined);
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += (message ? ' ' : '\t');
message += localize("replacing.editorPath", "Replacing {0} '{1}' with '{2}'.", "editorPath", sourceFileMapTarget, newSourceFileMapTarget["editorPath"]);
target = newSourceFileMapTarget;
}
@ -873,7 +844,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
selectedConfig.debugType = debugModeOn ? DebugType.debug : DebugType.run;
// startDebugging will trigger a call to resolveDebugConfiguration.
await vscode.debug.startDebugging(folder, selectedConfig, { noDebug: !debugModeOn });
await vscode.debug.startDebugging(folder, selectedConfig, {noDebug: !debugModeOn});
}
private async selectConfiguration(textEditor: vscode.TextEditor, pickDefault: boolean = true, onlyWorkspaceFolder: boolean = false): Promise<CppDebugConfiguration | undefined> {
@ -941,116 +912,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
}
}
private async expand(config: vscode.DebugConfiguration, folder: vscode.WorkspaceFolder | undefined): Promise<void> {
const folderPath: string | undefined = folder?.uri.fsPath || vscode.workspace.workspaceFolders?.[0].uri.fsPath;
const vars: ExpansionVars = config.variables ? config.variables : {};
vars.workspaceFolder = folderPath || '{workspaceFolder}';
vars.workspaceFolderBasename = folderPath ? path.basename(folderPath) : '{workspaceFolderBasename}';
const expansionOptions: ExpansionOptions = { vars, recursive: true };
return expandAllStrings(config, expansionOptions);
}
// Returns true when ALL steps succeed; stop all subsequent steps if one fails
private async deploySteps(config: vscode.DebugConfiguration, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
let succeeded: boolean = true;
const deployStart: number = new Date().getTime();
for (const step of config.deploySteps) {
succeeded = await this.singleDeployStep(config, step, cancellationToken);
if (!succeeded) {
break;
}
}
const deployEnd: number = new Date().getTime();
const telemetryProperties: { [key: string]: string } = {
Succeeded: `${succeeded}`,
IsDebugging: `${!config.noDebug || false}`
};
const telemetryMetrics: { [key: string]: number } = {
NumSteps: config.deploySteps.length,
Duration: deployEnd - deployStart
};
Telemetry.logDebuggerEvent('deploy', telemetryProperties, telemetryMetrics);
return succeeded;
}
private async singleDeployStep(config: vscode.DebugConfiguration, step: any, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
if ((config.noDebug && step.debug === true) || (!config.noDebug && step.debug === false)) {
// Skip steps that doesn't match current launch mode. Explicit true/false check, since a step is always run when debug is undefined.
return true;
}
switch (step.type) {
case StepType.command: {
// VS Code commands are the same regardless of which extension invokes them, so just invoke them here.
if (step.args && !Array.isArray(step.args)) {
logger.getOutputChannelLogger().showErrorMessage(localize('command.args.must.be.array', '"args" in command deploy step must be an array.'));
return false;
}
const returnCode: unknown = await vscode.commands.executeCommand(step.command, ...step.args);
return !returnCode;
}
case StepType.scp: {
if (!step.files || !step.targetDir || !step.host) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.scp', '"host", "files", and "targetDir" are required in scp steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
let files: vscode.Uri[] = [];
if (util.isString(step.files)) {
files = files.concat((await globAsync(step.files)).map(file => vscode.Uri.file(file)));
} else if (util.isArrayOfString(step.files)) {
for (const fileGlob of (step.files as string[])) {
files = files.concat((await globAsync(fileGlob)).map(file => vscode.Uri.file(file)));
}
} else {
logger.getOutputChannelLogger().showErrorMessage(localize('incorrect.files.type.scp', '"files" must be a string or an array of strings in scp steps.'));
return false;
}
const scpResult: util.ProcessReturnType = await scp(files, host, step.targetDir, config.scpPath, jumpHosts, cancellationToken);
if (!scpResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.ssh: {
if (!step.host || !step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.ssh', '"host" and "command" are required for ssh steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
const localForwards: util.ISshLocalForwardInfo[] = step.host.localForwards;
const continueOn: string = step.continueOn;
const sshResult: util.ProcessReturnType = await ssh(host, step.command, config.sshPath, jumpHosts, localForwards, continueOn, cancellationToken);
if (!sshResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.shell: {
if (!step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.shell', '"command" is required for shell steps.'));
return false;
}
const taskResult: util.ProcessReturnType = await util.spawnChildProcess(step.command, undefined, step.continueOn);
if (!taskResult.succeeded || cancellationToken?.isCancellationRequested) {
logger.getOutputChannelLogger().showErrorMessage(taskResult.output);
return false;
}
break;
}
default: {
logger.getOutputChannelLogger().appendLine(localize('deploy.step.type.not.supported', 'Deploy step type {0} is not supported.', step.type));
return false;
}
}
return true;
}
}
export interface IConfigurationAssetProvider {
@ -1203,7 +1064,7 @@ export class ConfigurationSnippetProvider implements vscode.CompletionItemProvid
items = [];
// Make a copy of each snippet since we are adding a comma to the end of the insertText.
this.snippets.forEach((item) => items.push({ ...item }));
this.snippets.forEach((item) => items.push({...item}));
items.map((item) => {
item.insertText = item.insertText + ','; // Add comma

Просмотреть файл

@ -1,340 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { stripEscapeSequences, isWindows, escapeStringForRegex } from '../common';
export type IDifferingHostConfirmationProvider =
(message: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export type IFingerprintConfirmationProvider =
(host: string, fingerprint: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export interface IInteraction {
canceled?: boolean;
postAction?: 'consume' | 'keep';
response?: string;
isPassword?: boolean;
continue?: boolean; // Continue without waiting for the program to finish or pause
}
export interface IInteractorDataDetails {
detectedServerKey?: string;
detail?: string;
}
export interface IInteractor {
id: string;
onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction>;
}
export class MitmInteractor implements IInteractor {
static ID = 'mitm';
constructor() { }
get id(): string {
return MitmInteractor.ID;
}
async onData(data: string): Promise<IInteraction> {
if (!!data.match('Port forwarding is disabled to avoid man-in-the-middle attacks.')) {
throw Error('Port forwarding is disabled to avoid man-in-the-middle attacks.');
}
return {};
}
}
export class FingerprintInteractor implements IInteractor {
static ID = 'fingerprint';
constructor(private readonly hostName: string, private readonly confirmationProvider: IFingerprintConfirmationProvider) { }
get id(): string {
return FingerprintInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const fingerprintMatcher: RegExp = /fingerprint\sis\s(.+)\./;
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
let fingerprintMatch: RegExpMatchArray | null;
if (
data.includes('Are you sure you want to continue connecting') &&
(fingerprintMatch = data.match(fingerprintMatcher))
) {
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(
this.hostName,
fingerprintMatch[1],
cancelToken
);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
} else if (
isWindows() &&
(data.includes('The authenticity of host ') || (data === '' && extraDetails?.detectedServerKey))
) {
// hack for #1195
// First line local server case (git ssh only gives the first line over ssh_askpass)
const key: string = extraDetails?.detectedServerKey || '(unknown)';
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(this.hostName, key, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export class DifferingHostKeyInteractor implements IInteractor {
static ID = 'differing host key';
constructor(private readonly confirmationProvider: IDifferingHostConfirmationProvider) { }
get id(): string {
return DifferingHostKeyInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, _extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
if (
data.includes('Are you sure you want to continue connecting') &&
data.includes('Offending key for IP in') &&
data.includes('Matching host key in')
) {
result.postAction = 'consume';
const message: string = data.substring(data.indexOf('Warning'), data.indexOf('Are')).trim();
const confirmation: string | undefined = await this.confirmationProvider(message, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IStringProvider =
(key?: string, detail?: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class PassphraseInteractor implements IInteractor {
static ID = 'passphrase';
constructor(private readonly passphraseProvider: IStringProvider) { }
get id(): string {
return PassphraseInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const lines: string[] = data.trim().split('\n');
if (lines.some(l => l.indexOf('Enter passphrase for') >= 0)) {
result.postAction = 'consume';
const passphrase: string | undefined = await this.passphraseProvider(undefined, undefined, cancelToken); // TODO keep track of the key name
if (typeof passphrase === 'string') {
result.response = passphrase;
result.isPassword = true;
} else {
result.canceled = true;
}
} else if (lines.some(l => l.indexOf('Identity added:') >= 0)) {
result.postAction = 'consume';
}
return result;
}
}
export function getExitCode(output: string, marker: string): number | undefined {
const regex: RegExp = new RegExp(`${marker}##([0-9]*)##`);
const match: RegExpExecArray | null = regex.exec(output);
if (match) {
try {
const num: number = parseInt(match[1]);
return Number.isNaN(num) ? undefined : num;
} catch (err) {
return undefined;
}
}
return 0;
}
/**
* Matches SSH password prompt of format:
* 's password:
* or
* Password:
* not
* 's old password:
* 's new password:
*/
function getPasswordPrompt(data: string, details?: IInteractorDataDetails): { user?: string; message?: string } | undefined {
if (data.includes('Password:')) {
// Password prompt for unspecified user
return { user: '' };
}
// Got \r\r\n as a line ending here
const match: RegExpMatchArray | null = stripEscapeSequences(data).match(/([a-zA-Z0-9\-_@\.]*)'s password:/);
if (match) {
return {
user: match[1],
message: details ? details.detail : undefined
};
}
return undefined;
}
export class PasswordInteractor implements IInteractor {
static ID = 'password';
constructor(private readonly passwordProvider: IStringProvider) { }
get id(): string {
return PasswordInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pwPrompt: { user?: string; message?: string } | undefined = getPasswordPrompt(data, extraDetails);
if (pwPrompt && typeof pwPrompt.user === 'string') {
result.postAction = 'consume';
const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken);
if (typeof password === 'string') {
result.response = password;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IVerificationCodeProvider =
(msg: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class TwoFacInteractor implements IInteractor {
static ID = '2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return TwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Verification code:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter verification code', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
// https://github.com/microsoft/vscode-remote-release/issues/2170
export class DuoTwoFacInteractor implements IInteractor {
static ID = 'duo-2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return DuoTwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Passcode:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter passcode', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export class ContinueOnInteractor implements IInteractor {
static ID = 'continueOn';
constructor(private readonly continueOn: string) { }
get id(): string {
return ContinueOnInteractor.ID;
}
async onData(data: string, _cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pattern: string = escapeStringForRegex(this.continueOn);
const re: RegExp = new RegExp(pattern, 'g');
if (data.match(re)) {
result.continue = true;
}
return result;
}
}
export class ComposedInteractor implements IInteractor {
constructor(private readonly interactors: IInteractor[]) { }
get id(): string {
return 'composed';
}
async onData(data: string): Promise<IInteraction> {
for (const interactor of this.interactors) {
const result: IInteraction = await interactor.onData(data);
if (result.postAction === 'consume') {
return result;
}
}
return { postAction: 'keep' };
}
}
export interface ISystemInteractor {
createTerminal(options: vscode.TerminalOptions): vscode.Terminal;
onDidCloseTerminal: typeof vscode.window.onDidCloseTerminal;
onDidWriteTerminalData: typeof vscode.window.onDidWriteTerminalData;
}
export const defaultSystemInteractor: ISystemInteractor = {
createTerminal: vscode.window.createTerminal,
onDidCloseTerminal: vscode.window.onDidCloseTerminal,
onDidWriteTerminalData: vscode.window.onDidWriteTerminalData
};

Просмотреть файл

@ -1,98 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
import { defaultSystemInteractor } from './commandInteractors';
import { runSshTerminalCommandWithLogin } from './sshCommandRunner';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export async function scp(files: vscode.Uri[], host: ISshHostInfo, targetDir: string, scpPath?: string, jumpHosts?: ISshHostInfo[], cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// upper case P
args.push('-P', `${host.port}`);
}
args.push(files.map(uri => `"${uri.fsPath}"`).join(' '), `${getFullHostAddressNoPort(host)}:${targetDir}`);
return runSshTerminalCommandWithLogin(host, { systemInteractor: defaultSystemInteractor, nickname: 'scp', command: `"${scpPath || 'scp'}" ${args.join(' ')}`, token: cancellationToken });
}
export function ssh(host: ISshHostInfo, command: string, sshPath?: string, jumpHosts?: ISshHostInfo[], localForwards?: ISshLocalForwardInfo[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// lower case p
args.push('-p', `${host.port}`);
}
if (localForwards) {
localForwards.forEach(info => args.push(...localForwardToArgs(info)));
}
args.push(getFullHostAddressNoPort(host), `"${command}"`);
return runSshTerminalCommandWithLogin(host, {
systemInteractor: defaultSystemInteractor,
command: `"${sshPath || 'ssh'}" ${args.join(' ')}`,
nickname: 'ssh',
continueOn,
token: cancellationToken
});
}
/**
* Takes one local forward info and convert it to '-L' args in ssh.
*/
function localForwardToArgs(localForward: ISshLocalForwardInfo): string[] {
// Do not combine error checking and arg conversion for clarity.
if (localForward.localSocket && (localForward.bindAddress || localForward.port)) {
throw Error(localize('local.forward.local.conflict', '"localSocket" cannot be specifed at the same time with "bindAddress" or "port" in localForwards'));
}
if (!localForward.localSocket && !localForward.port) {
throw Error(localize('local.forward.local.missing', '"port" or "localSocket" required in localForwards'));
}
if (localForward.remoteSocket && (localForward.host || localForward.hostPort)) {
throw Error(localize('local.forward.remote.conflict', '"remoteSocket" cannot be specifed at the same time with "host" or "hostPort" in localForwards'));
}
if (!localForward.remoteSocket && (!localForward.host || !localForward.hostPort)) {
throw Error(localize('local.forward.remote.missing', '"host" and "hostPort", or "remoteSocket" required in localForwards'));
}
let arg: string = '';
if (localForward.localSocket) {
arg += `${localForward.localSocket}:`;
}
if (localForward.bindAddress) {
arg += `${localForward.bindAddress}:`;
}
if (localForward.port) {
arg += `${localForward.port}:`;
}
if (localForward.remoteSocket) {
arg += `${localForward.remoteSocket}`;
}
if (localForward.host && localForward.hostPort) {
arg += `${localForward.host}:${localForward.hostPort}`;
}
return ['-L', arg];
}
/** user@host */
function getFullHostAddressNoPort(host: ISshHostInfo): string {
return host.user ? `${host.user}@${host.hostName}` : `${host.hostName}`;
}
function getFullHostAddress(host: ISshHostInfo): string {
const fullHostName: string = getFullHostAddressNoPort(host);
return host.port ? `${fullHostName}:${host.port}` : fullHostName;
}

Просмотреть файл

@ -1,518 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import {
DifferingHostKeyInteractor,
DuoTwoFacInteractor,
FingerprintInteractor,
IInteractor,
MitmInteractor,
PassphraseInteractor,
PasswordInteractor,
TwoFacInteractor,
ContinueOnInteractor,
ISystemInteractor,
IInteraction
} from './commandInteractors';
import { isWindows, ISshHostInfo, splitLines, stripEscapeSequences, ProcessReturnType } from '../common';
import { getOutputChannelLogger } from '../logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export class CanceledError extends Error {
constructor() {
super(localize('ssh.canceled', 'SSH command canceled'));
}
}
export interface ICommandResult {
stdout: string;
stderr: string;
}
export function showPassphraseInputBox(
keyName?: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const keyStr: string = keyName ? `"${keyName}"` : '';
const msg: string = localize('ssh.passphrase.input.box', 'Enter passphrase for ssh key {0}', keyStr);
return showInputBox(msg, prompt, cancelToken);
}
export function showPasswordInputBox(
user: string | undefined,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const msg: string = user ? localize('ssh.enter.password.for.user', 'Enter password for user "{0}"', user) : localize('ssh_message_enterPassword', 'Enter password');
return showInputBox(msg, prompt, cancelToken);
}
export function showVerificationCodeInputBox(
msg: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showInputBox(msg, undefined, cancelToken);
}
export async function showInputBox(
msg: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.InputBox = vscode.window.createInputBox();
quickPick.title = msg;
quickPick.prompt = prompt;
quickPick.password = true;
quickPick.ignoreFocusOut = true;
let isAccepted: boolean = false;
quickPick.onDidAccept(() => {
isAccepted = true;
const passphrase: string = quickPick.value;
quickPick.dispose();
resolve(passphrase);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
reject(new CanceledError());
quickPick.dispose();
});
}
});
}
class ConfirmationItem implements vscode.QuickPickItem, vscode.MessageItem {
title: string;
isCloseAffordance: boolean = true;
constructor(public label: string, public value: string) {
this.title = label;
}
}
const continueConfirmationPlaceholder: string = localize('ssh.continue.confirmation.placeholder', 'Are you sure you want to continue?');
export async function showHostKeyConfirmation(
host: string,
fingerprint: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(
localize('ssh.host.key.confirmation.title', '"{0}" has fingerprint "{1}".', host, fingerprint),
continueConfirmationPlaceholder,
cancelToken
);
}
export async function showDifferingHostConfirmation(
message: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(message, continueConfirmationPlaceholder, cancelToken);
}
async function showConfirmationPicker(
title: string,
placeholder: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.QuickPick<ConfirmationItem> = vscode.window.createQuickPick<ConfirmationItem>();
quickPick.canSelectMany = false;
quickPick.items = [new ConfirmationItem(localize('continue', 'Continue'), 'yes'), new ConfirmationItem(localize('cancel', 'Cancel'), 'no')];
quickPick.title = title;
quickPick.placeholder = placeholder;
let isAccepted: boolean = false;
quickPick.onDidAccept(async () => {
isAccepted = true;
const value: string = quickPick.selectedItems[0].value;
quickPick.dispose();
resolve(value);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
quickPick.hide();
reject(new CanceledError());
});
}
});
}
export interface ITerminalCommandWithLoginArgs {
systemInteractor: ISystemInteractor;
command: string;
nickname: string;
marker?: string;
usedInteractors?: Set<string>;
interactor?: IInteractor;
cwd?: string;
token?: vscode.CancellationToken;
continueOn?: string;
revealTerminal?: vscode.Event<void>;
}
export async function runSshTerminalCommandWithLogin(
host: ISshHostInfo,
terminalArgs: ITerminalCommandWithLoginArgs,
showLoginTerminal = false
): Promise<ProcessReturnType> {
const interactors: IInteractor[] = [];
if (terminalArgs.interactor) {
interactors.push(terminalArgs.interactor);
}
if (!showLoginTerminal) {
interactors.push(
new MitmInteractor(),
new FingerprintInteractor(host.hostName, showHostKeyConfirmation),
new PassphraseInteractor(showPassphraseInputBox),
new DifferingHostKeyInteractor(showDifferingHostConfirmation),
new PasswordInteractor(showPasswordInputBox),
new TwoFacInteractor(showVerificationCodeInputBox),
new DuoTwoFacInteractor(showVerificationCodeInputBox)
);
}
if (terminalArgs.continueOn) {
interactors.push(new ContinueOnInteractor(terminalArgs.continueOn));
}
// This terminal is always local
const result: ProcessReturnType = await runInteractiveSshTerminalCommand({
systemInteractor: terminalArgs.systemInteractor,
command: terminalArgs.command,
interactors,
usedInteractors: terminalArgs.usedInteractors,
nickname: terminalArgs.nickname,
token: terminalArgs.token,
marker: terminalArgs.marker,
revealTerminal: terminalArgs.revealTerminal,
showLoginTerminal,
cwd: terminalArgs.cwd ? vscode.Uri.file(terminalArgs.cwd) : undefined
});
return result;
}
export interface ITerminalCommandArgs {
systemInteractor: ISystemInteractor;
command: string;
interactors?: IInteractor[];
nickname: string;
usedInteractors?: Set<string>;
sendText?: string;
cwd?: vscode.Uri;
terminalIsWindows?: boolean;
token?: vscode.CancellationToken;
marker?: string;
revealTerminal?: vscode.Event<void>;
showLoginTerminal?: boolean; // If true, respect the showLoginTerminal setting
}
export function getPauseLogMarker(uuid: string): string {
return `${uuid}: pauseLog`;
}
export function getResumeLogMarker(uuid: string): string {
return `${uuid}: resumeLog`;
}
export function runInteractiveSshTerminalCommand(args: ITerminalCommandArgs): Promise<ProcessReturnType> {
const disposables: vscode.Disposable[] = [];
const { systemInteractor, command, interactors, nickname, token } = args;
let logIsPaused: boolean = false;
return new Promise(async (resolve, reject) => {
let stdout: string = '';
let windowListener: vscode.Disposable | undefined;
let terminalListener: vscode.Disposable | undefined;
let terminal: vscode.Terminal | undefined;
let tokenListener: vscode.Disposable;
let continueWithoutExiting: boolean = false;
const clean = () => {
if (terminalListener) {
terminalListener.dispose();
terminalListener = undefined;
}
if (terminal) {
terminal.dispose();
terminal = undefined;
}
if (windowListener) {
windowListener.dispose();
windowListener = undefined;
}
if (tokenListener) {
tokenListener.dispose();
}
disposables.forEach(disposable => disposable.dispose());
};
const done = (cancel: boolean = false, noClean: boolean = false, exitCode?: number) => {
if (!noClean) {
clean();
}
getOutputChannelLogger().appendLine(cancel ? localize('ssh.terminal.command.canceled', '"{0}" terminal command canceled.', nickname) : localize('ssh.terminal.command.done', '"{0}" terminal command done.', nickname));
if (cancel) {
if (continueWithoutExiting) {
getOutputChannelLogger().showWarningMessage(localize('ssh.continuing.command.canceled', 'Task \'{0}\' is canceled, but the underlying command may not be terminated. Please check manually.', command));
}
return reject(new CanceledError());
}
// When using showLoginTerminal, stdout include the passphrase prompt, etc. Try to get just the command output on the last line.
const actualOutput: string | undefined = cancel ? '' : lastNonemptyLine(stdout);
resolve({ succeeded: !exitCode, exitCode, output: actualOutput || '' });
};
const failed = (error?: any) => {
clean();
getOutputChannelLogger().showErrorMessage(localize('ssh.process.failed', '"{0}" process failed: {1}', nickname, error));
reject(error);
};
const handleOutputLogging = (data: string): void => {
let nextPauseState: boolean | undefined;
if (args.marker) {
const pauseMarker: string = getPauseLogMarker(args.marker);
const pauseIdx: number = data.lastIndexOf(pauseMarker);
if (pauseIdx >= 0) {
data = data.substring(0, pauseIdx + pauseMarker.length);
nextPauseState = true;
}
const resumeIdx: number = data.lastIndexOf(getResumeLogMarker(args.marker));
if (resumeIdx >= 0) {
data = data.substring(resumeIdx);
nextPauseState = false;
}
}
// Log the chunk of data that includes the pause/resume markers,
// so unpause first and pause after logging
if (!logIsPaused) {
logReceivedData(data, nickname);
}
if (typeof nextPauseState === 'boolean') {
logIsPaused = nextPauseState;
}
};
const handleTerminalOutput = async (dataWrite: vscode.TerminalDataWriteEvent): Promise<void> => {
handleOutputLogging(dataWrite.data);
stdout += dataWrite.data;
if (interactors) {
for (const interactor of interactors) {
try {
const interaction: IInteraction = await interactor.onData(stdout);
if (interaction.postAction === 'consume') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
stdout = '';
}
if (interaction.canceled) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
done(true);
return;
}
if (interaction.continue) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
continueWithoutExiting = true;
done(false, true);
return;
}
if (typeof interaction.response === 'string') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
if (terminal) {
terminal.sendText(`${interaction.response}\n`);
const logOutput: string = interaction.isPassword
? interaction.response.replace(/./g, '*')
: interaction.response;
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, logOutput));
}
}
} catch (e) {
failed(e);
}
}
}
};
if (token) {
tokenListener = token.onCancellationRequested(() => {
done(true);
});
}
const terminalIsWindows: boolean = typeof args.terminalIsWindows === 'boolean' ? args.terminalIsWindows : isWindows();
try {
// the terminal process should not fail, but exit cleanly
let shellArgs: string | string[];
if (args.sendText) {
shellArgs = '';
} else {
shellArgs = terminalIsWindows ? `/c (${command})\nexit /b %ErrorLevel%` : ['-c', `${command}\nexit $?`];
}
const options: vscode.TerminalOptions = {
cwd:
args.cwd ||
(terminalIsWindows
? vscode.Uri.file(os.homedir() || 'c:\\')
: vscode.Uri.file(os.homedir() || '/')),
name: nickname,
shellPath: getShellPath(terminalIsWindows),
shellArgs,
hideFromUser: true
};
let terminalDataHandlingQueue: Promise<void> = Promise.resolve();
terminalListener = systemInteractor.onDidWriteTerminalData(async e => {
if (e.terminal !== terminal) {
return;
}
terminalDataHandlingQueue = terminalDataHandlingQueue.finally(() => handleTerminalOutput(e));
});
terminal = systemInteractor.createTerminal(options);
if (args.revealTerminal) {
disposables.push(
args.revealTerminal(() => {
if (terminal) {
terminal.show();
}
})
);
}
if (args.sendText) {
const sendText: string = terminalIsWindows ? `(${args.sendText})\nexit /b %ErrorLevel%` : `${args.sendText}\nexit $?`;
terminal.sendText(sendText);
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, args.sendText));
}
if (args.showLoginTerminal) {
terminal.show();
}
windowListener = systemInteractor.onDidCloseTerminal(t => {
if (t === terminal) {
terminal = undefined; // Is already disposed
done(false, false, t.exitStatus?.code);
}
});
} catch (error) {
failed(error);
}
});
}
function getShellPath(_isWindows: boolean): string {
if (_isWindows) {
// Some users don't have cmd.exe on the path...
if (process.env.SystemRoot) {
// This var should always exist but be paranoid
const cmdPath: string = path.join(process.env.SystemRoot, 'System32', 'cmd.exe');
return cmdPath;
} else {
return 'cmd.exe';
}
} else {
// Note - can't rely on having sh in path (#590), and can't check the disk (bc remote terminals)
return '/bin/sh';
}
}
function logReceivedData(data: string, nickname: string): void {
const logData: string = data.replace(/\r?\n$/, ''); // Trim single trailing newline for nicer log
if (logData === ' ') {
// From the sleep command that must periodically echo ' '
return;
}
const markedLines: string = logData
.split(/\n/)
.map(line => `${nickname}> ${line}`)
.join('\n');
getOutputChannelLogger().appendLine(markedLines);
}
function lastNonemptyLine(str: string): string | undefined {
const lines: string[] = splitLines(str);
if (isWindows()) {
let outputContainingPipeError: string = '';
for (let i: number = lines.length - 1; i >= 0; i--) {
const strippedLine: string = stripEscapeSequences(lines[i]);
if (strippedLine.match(/The process tried to write to a nonexistent pipe/)) {
outputContainingPipeError = strippedLine;
continue;
}
if (!!strippedLine) {
return strippedLine;
}
}
if (outputContainingPipeError) {
return outputContainingPipeError;
}
}
const nonEmptyLines: string[] = lines.filter(l => !!l);
return nonEmptyLines[nonEmptyLines.length - 1];
}

Просмотреть файл

@ -18,9 +18,9 @@ import * as https from 'https';
import * as tmp from 'tmp';
import { ClientRequest, OutgoingHttpHeaders } from 'http';
import * as nls from 'vscode-nls';
import { Readable } from 'stream';
import * as jsonc from 'comment-json';
import { TargetPopulation } from 'vscode-tas-client';
import { CppSettings } from './LanguageServer/settings';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -320,13 +320,10 @@ export function resolveCachePath(input: string | undefined, additionalEnvironmen
return resolvedPath;
}
export function isWindows(): boolean {
return os.platform() === 'win32';
}
export function defaultExePath(): string {
const isWindows: boolean = os.platform() === 'win32';
const exePath: string = path.join('${fileDirname}', '${fileBasenameNoExtension}');
return isWindows() ? exePath + '.exe' : exePath;
return isWindows ? exePath + '.exe' : exePath;
}
export function findExePathInArgs(args: string[]): string | undefined {
@ -572,9 +569,9 @@ export function checkDirectoryExistsSync(dirPath: string): boolean {
}
/** Test whether a relative path exists */
export function checkPathExistsSync(path: string, relativePath: string, _isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
export function checkPathExistsSync(path: string, relativePath: string, isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
let pathExists: boolean = true;
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && _isWindows && !isWSL && fs.existsSync(path + ".exe");
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && isWindows && !isWSL && fs.existsSync(path + ".exe");
if (!fs.existsSync(path)) {
if (existsWithExeAdded(path)) {
path += ".exe";
@ -713,83 +710,32 @@ export function execChildProcess(process: string, workingDirectory?: string, cha
});
}
export interface ProcessReturnType {
succeeded: boolean;
exitCode?: number | NodeJS.Signals;
output: string;
}
export function spawnChildProcess(process: string, args: string[], workingDirectory: string,
dataCallback: (stdout: string) => void, errorCallback: (stderr: string) => void): Promise<void> {
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, cancellationToken);
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Information" || settings.loggingLevel === "Debug") {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}\n${programOutput.stderr || programOutput.stdout}\n`);
}
if (programOutput.exitCode) {
return { succeeded: false, exitCode, output: programOutput.stderr || programOutput.stdout || localize('process.exited', 'Process exited with code {0}', exitCode) };
} else {
let stdout: string;
if (programOutput.stdout.length) {
// Type system doesn't work very well here, so we need call toString
stdout = programOutput.stdout;
} else {
stdout = localize('process.succeeded', 'Process executed successfully.');
}
return { succeeded: true, exitCode, output: stdout };
}
}
return new Promise<void>(function (resolve, reject): void {
const child: child_process.ChildProcess = child_process.spawn(process, args, { cwd: workingDirectory });
interface ProcessOutput {
exitCode?: number | NodeJS.Signals;
stdout: string;
stderr: string;
}
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
return new Promise(async (resolve, reject) => {
let proc: child_process.ChildProcess;
if (await isExecutable(program)) {
proc = child_process.spawn(`.${isWindows() ? '\\' : '/'}${path.basename(program)}`, args, { shell: true, cwd: path.dirname(program) });
} else {
proc = child_process.spawn(program, args, { shell: true });
}
const cancellationTokenListener: vscode.Disposable | undefined = cancellationToken?.onCancellationRequested(() => {
getOutputChannelLogger().appendLine(localize('killing.process', 'Killing process {0}', program));
proc.kill();
});
const clean = () => {
proc.removeAllListeners();
if (cancellationTokenListener) {
cancellationTokenListener.dispose();
}
};
let stdout: string = '';
let stderr: string = '';
if (proc.stdout) {
proc.stdout.on('data', data => {
stdout += data.toString();
if (continueOn) {
const continueOnReg: string = escapeStringForRegex(continueOn);
if (stdout.search(continueOnReg)) {
resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
}
}
const stdout: Readable | null = child.stdout;
if (stdout) {
stdout.on('data', (data) => {
dataCallback(`${data}`);
});
}
if (proc.stderr) {
proc.stderr.on('data', data => stderr += data.toString());
const stderr: Readable | null = child.stderr;
if (stderr) {
stderr.on('data', (data) => {
errorCallback(`${data}`);
});
}
proc.on('close', (code, signal) => {
clean();
resolve({ exitCode: code || signal, stdout: stdout.trim(), stderr: stderr.trim() });
});
proc.on('error', error => {
clean();
reject(error);
child.on('exit', (code: number) => {
if (code !== 0) {
reject(new Error(localize("process.exited.with.code", "{0} exited with error code {1}", process, code)));
} else {
resolve();
}
});
});
}
@ -980,6 +926,7 @@ function resolveWindowsEnvironmentVariables(str: string): string {
}
function legacyExtractArgs(argsString: string): string[] {
const isWindows: boolean = os.platform() === 'win32';
const result: string[] = [];
let currentArg: string = "";
let isWithinDoubleQuote: boolean = false;
@ -1003,7 +950,7 @@ function legacyExtractArgs(argsString: string): string[] {
}
} else if (c === '\'') {
// On Windows, a single quote string is not allowed to join multiple args into a single arg
if (!isWindows()) {
if (!isWindows) {
if (!isWithinDoubleQuote) {
isWithinSingleQuote = !isWithinSingleQuote;
}
@ -1462,38 +1409,3 @@ export function isVsCodeInsiders(): boolean {
extensionPath.includes(".vscode-server-exploration");
}
export function stripEscapeSequences(str: string): string {
return str
.replace(/\x1b\[\??[0-9]{0,3}(;[0-9]{1,3})?[a-zA-Z]/g, '')
.replace(/\u0008/g, '')
.replace(/\r/g, '');
}
export function splitLines(data: string): string[] {
return data.split(/\r?\n/g);
}
export function escapeStringForRegex(str: string): string {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}
export function replaceAll(str: string, searchValue: string, replaceValue: string): string {
const pattern: string = escapeStringForRegex(searchValue);
const re: RegExp = new RegExp(pattern, 'g');
return str.replace(re, replaceValue);
}
export interface ISshHostInfo {
hostName: string;
user?: string;
port?: number | string;
}
export interface ISshLocalForwardInfo {
bindAddress?: string;
port?: number | string;
host?: string;
hostPort?: number | string;
localSocket?: string;
remoteSocket?: string;
}

Просмотреть файл

@ -1,133 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { isString, replaceAll } from './common';
import { getOutputChannelLogger } from './logger';
/**
* Support ExpansionVars (${var}), env (${env:var}), and optionally VS CODE commands (${command:commandID}).
* Supported format follows https://code.visualstudio.com/docs/editor/variables-reference
* Expand options and functions are mofidifed from https://github.com/microsoft/vscode-cmake-tools/blob/main/src/expand.ts
*/
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export interface ExpansionVars {
[key: string]: string;
workspaceFolder: string;
workspaceFolderBasename: string;
}
export interface ExpansionOptions {
vars: ExpansionVars;
doNotSupportCommands?: boolean;
recursive?: boolean;
}
export async function expandAllStrings(obj: any, options: ExpansionOptions): Promise<void> {
if (Array.isArray(obj) || (obj !== null && typeof obj === 'object')) {
for (const key of Object.keys(obj)) {
if (isString(obj[key])) {
obj[key] = await expandString(obj[key], options);
} else {
await expandAllStrings(obj[key], options);
}
}
}
}
export async function expandString(input: string, options: ExpansionOptions): Promise<string> {
const MAX_RECURSION: number = 10;
let result: string = input;
let didReplacement: boolean = false;
let i: number = 0;
do {
// TODO: consider a full circular reference check?
[result, didReplacement] = await expandStringImpl(result, options);
i++;
} while (i < MAX_RECURSION && options.recursive && didReplacement);
if (i === MAX_RECURSION && didReplacement) {
getOutputChannelLogger().showErrorMessage(localize('max.recursion.reached', 'Reached max string expansion recursion. Possible circular reference.'));
}
return replaceAll(result, '${dollar}', '$');
}
/** Returns [expandedString, didReplacement] */
async function expandStringImpl(input: string, options: ExpansionOptions): Promise<[string, boolean]> {
if (!input) {
return [input, false];
}
// We accumulate a list of substitutions that we need to make, preventing
// recursively expanding or looping forever on bad replacements
const subs: Map<string, string> = new Map<string, string>();
const var_re: RegExp = /\$\{(\w+)\}/g;
let match: RegExpMatchArray | null = null;
while ((match = var_re.exec(input))) {
const full: string = match[0];
const key: string = match[1];
if (key !== 'dollar') {
// Replace dollar sign at the very end of the expanding process
const repl: string = options.vars[key];
if (!repl) {
getOutputChannelLogger().showWarningMessage(localize('invalid.var.reference', 'Invalid variable reference {0} in string: {1}.', full, input));
} else {
subs.set(full, repl);
}
}
}
// Regular expression for variable value (between the variable suffix and the next ending curly bracket):
// .+? matches any character (except line terminators) between one and unlimited times,
// as few times as possible, expanding as needed (lazy)
const varValueRegexp: string = ".+?";
const env_re: RegExp = RegExp(`\\$\\{env:(${varValueRegexp})\\}`, "g");
while ((match = env_re.exec(input))) {
const full: string = match[0];
const varname: string = match[1];
if (process.env[varname] === undefined) {
getOutputChannelLogger().showWarningMessage(localize('env.var.not.found', 'Environment variable {0} not found', varname));
}
const repl: string = process.env[varname] || '';
subs.set(full, repl);
}
const command_re: RegExp = RegExp(`\\$\\{command:(${varValueRegexp})\\}`, "g");
while ((match = command_re.exec(input))) {
if (options.doNotSupportCommands) {
getOutputChannelLogger().showWarningMessage(localize('commands.not.supported', 'Commands are not supported for string: {0}.', input));
break;
}
const full: string = match[0];
const command: string = match[1];
if (subs.has(full)) {
continue; // Don't execute commands more than once per string
}
try {
const command_ret: unknown = await vscode.commands.executeCommand(command, options.vars.workspaceFolder);
subs.set(full, `${command_ret}`);
} catch (e: any) {
getOutputChannelLogger().showWarningMessage(localize('exception.executing.command', 'Exception while executing command {0} for string: {1} {2}.', command, input, e));
}
}
let result: string = input;
let didReplacement: boolean = false;
subs.forEach((value, key) => {
if (value !== key) {
result = replaceAll(result, key, value);
didReplacement = true;
}
});
return [result, didReplacement];
}

Просмотреть файл

@ -89,11 +89,11 @@ export async function deactivate(): Promise<void> {
}
}
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }, metrics?: { [key: string]: number }): void {
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "cppdbg/VS/Diagnostics/Debugger/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties);
}
};

Просмотреть файл

@ -14,7 +14,6 @@
"include": [
"test/**/*.ts",
"tools/**/*.ts",
"ui/**/*.ts",
"./vscode*.d.ts"
"ui/**/*.ts"
]
}

Просмотреть файл

@ -1,46 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as assert from "assert";
import { ExpansionOptions, expandAllStrings, expandString } from "../../src/expand";
suite('Var expansion validation', () => {
test('Expand all strings', async () => {
const input: object = {
in1: "${test2}",
in2: "${test4}",
in3: [
"${test3}",
{
in4: "${test3}"
}
]
};
const variables: object = {
test1: "t1",
test2: "${dollar}{${test1}}",
test3: "test${test2}test:${env:envtest}:${dollar}test",
test4: "${test4}"
};
const expansionOptions: ExpansionOptions = {
vars: {
workspaceFolder: '{workspaceFolder}',
workspaceFolderBasename: '{workspaceFolderBasename}',
...variables
},
recursive: true
};
await expandAllStrings(input, expansionOptions);
assert.deepStrictEqual(input, {
in1: "${t1}",
in2: "${test4}",
in3: [
"test${t1}test::$test",
{
in4: "test${t1}test::$test"
}
]
});
});
});

Просмотреть файл

@ -53,7 +53,7 @@ function updateDefaults(object: any, defaults: any): any {
}
function refReplace(definitions: any, ref: any): any {
// $ref is formatted as "#/definitions/ObjectName"
// $ref is formatted as "#/definitions/ObjectName"
const referenceStringArray: string[] = ref['$ref'].split('/');
// Getting "ObjectName"
@ -82,7 +82,11 @@ function replaceReferences(definitions: any, objects: any): any {
// Handle 'anyOf' with references
if (objects[key].hasOwnProperty('anyOf')) {
objects[key].anyOf = replaceReferences(definitions, objects[key].anyOf);
for (const index in objects[key].anyOf) {
if (objects[key].anyOf[index].hasOwnProperty('$ref')) {
objects[key].anyOf[index] = refReplace(definitions, objects[key].anyOf[index]);
}
}
}
// Recursively replace references if this object has properties.
@ -91,15 +95,10 @@ function replaceReferences(definitions: any, objects: any): any {
objects[key].properties = updateDefaults(objects[key].properties, objects[key].default);
}
// Items in array contains ref
// Recursively replace references if the array has objects in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null && objects[key].items.hasOwnProperty('$ref')) {
objects[key].items = refReplace(definitions, objects[key].items);
}
// Recursively replace references if the array has objects that contains ref in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null) {
objects[key].items = replaceReferences(definitions, objects[key].items);
}
}
return objects;

Просмотреть файл

@ -193,313 +193,6 @@
}
}
},
"Variables": {
"type": "object",
"description": "%c_cpp.debuggers.variables.description%",
"default": {
"<variable-name>": "<variable-value>"
},
"properties": {},
"additionalProperties": {
"type": "string",
"description": "%c_cpp.debuggers.variables.properties.description%",
"default": ""
}
},
"VsCodeCommand": {
"type": "object",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": "",
"enum": [
"command"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.command.description%",
"default": ""
},
"args": {
"type": "array",
"description": "%c_cpp.debuggers.vsCodeCommand.args.description%",
"items": {
"type": "string"
}
}
}
},
"Host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"DeploySteps": {
"type": "array",
"description": "%c_cpp.debuggers.deploySteps.description%",
"items": {
"anyOf": [
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": {},
"required": [
"type",
"files",
"host",
"targetDir"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": "",
"enum": [
"scp"
]
},
"files": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "%c_cpp.debuggers.deploySteps.scp.files.description%",
"default": ""
},
"host": {
"$ref": "#/definitions/Host"
},
"targetDir": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.targetDir.description%",
"default": ""
},
"scpPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.scpPath.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": {},
"required": [
"type",
"host",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": "",
"enum": [
"ssh"
]
},
"host": {
"$ref": "#/definitions/Host"
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.command.description%",
"default": ""
},
"sshPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.sshPath.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": "",
"enum": [
"shell"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.command.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"$ref": "#/definitions/VsCodeCommand"
}
]
},
"default": []
},
"CppdbgLaunchOptions": {
"type": "object",
"required": [
@ -560,8 +253,8 @@
},
"launchCompleteCommand": {
"enum": [
"exec-run",
"exec-continue",
"exec-run",
"exec-continue",
"None"
],
"description": "%c_cpp.debuggers.launchCompleteCommand.description%",
@ -706,12 +399,6 @@
"$ref": "#/definitions/HardwareBreakpoints",
"description": "%c_cpp.debuggers.hardwareBreakpoints.description%",
"default": {}
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},
@ -826,12 +513,6 @@
"symbolLoadInfo": {
"$ref": "#/definitions/SymbolLoadInfo",
"description": "%c_cpp.debuggers.symbolLoadInfo.description%"
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},

Просмотреть файл

@ -15,7 +15,7 @@
},
"include": [
"src/**/*.ts",
"./vscode*.d.ts",
"./node_modules/vscode/vscode.d.ts",
"./node_modules/vscode/lib/*"
]
}

Просмотреть файл

@ -290,14 +290,6 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe"
integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==
"@types/glob@^7.1.3":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/json-schema@*", "@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
@ -313,11 +305,6 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@ -365,6 +352,11 @@
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd"
integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==
"@types/vscode@1.65.0":
version "1.65.0"
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.65.0.tgz#042dd8d93c32ac62cb826cd0fa12376069d1f448"
integrity sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==
"@types/which@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
@ -3534,11 +3526,6 @@ kind-of@^6.0.0, kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
last-run@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
@ -4494,14 +4481,6 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prompts@^2.1.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
dependencies:
kleur "^3.0.3"
sisteransi "^1.0.5"
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -4970,11 +4949,6 @@ signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@ -5867,15 +5841,6 @@ vscode-debugprotocol@1.38.0, vscode-debugprotocol@^1.35.0:
resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.38.0.tgz#7a9bcd457e6642f48fabef114c0fa1c25a2fb1e7"
integrity sha512-oam9iSjNfXSn71a8bmNsXv8k/rIKSOcllIPrFnNgxd1EMBpfnum+gb7lmRpcH0zSjGb+OH8Ncn8B5tv8srWbNQ==
vscode-dts@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/vscode-dts/-/vscode-dts-0.3.3.tgz#e5ef3afe76182875b252cca7f449938e4a0bf28a"
integrity sha512-JfOsWL0NvfVw0UF9bcTjlv1Onz3Ted7cgpPWKWMnHGB+72t/tn8WFDeKLZO42l2k9KJq/NGS9rFC5gZbyI4FTg==
dependencies:
minimist "^1.2.0"
prompts "^2.1.0"
rimraf "^3.0.0"
vscode-jsonrpc@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9"