Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve and replace commands for next command #92697

Closed
wants to merge 3 commits into from
Closed

Resolve and replace commands for next command #92697

wants to merge 3 commits into from

Conversation

davidruhmann
Copy link

This PR fixes #89758

Which will add support for the use case of using command and environment values in the configuration as they are resolved for subsequent command executions. This enables the following use case.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Docker Attach",
            "type": "coreclr",
            "request": "attach",
            "pipeTransport": {
                "pipeProgram": "docker",
                "pipeArgs": [
                    "exec", "-i", "${command:vscode-docker.containers.select}"
                ],
                "debuggerPath": "/root/vsdbg/vsdbg",
                "pipeCwd": "${workspaceRoot}",
                "quoteArgs": false
            },
            "processId": "${command:pickRemoteProcess}",
            "sourceFileMap": {
                "/app": "${workspaceRoot}"
            },
            "justMyCode": true
        }
    ]
}

resolveDebugConfigurationWithSubstitutedVariables does not work for this use case as both commands are resolved/executed before replacement occurs. ${command:pickRemoteProcess} needs the value from ${command:vscode-docker.containers.select} in the config object passed to it during execution.

@weinand
Copy link
Contributor

weinand commented Mar 16, 2020

@davidruhmann what is exactly the approach behind your change?
What would we add to the variables documentation to explain the behavior to users?

(Don't assume that JSON properties are ordered. JSON objects are dictionaries, not sequential "programs")

@weinand weinand added the debug Debug viewlet, configurations, breakpoints, adapter issues label Mar 16, 2020
@davidruhmann
Copy link
Author

Definitely. Appreciate your taking a look at this.

My approach to the change was to be as backwards compatible as possible and not change the input or output of the public functions.

All the changes culminate around making this line pass in an object with the known replacements inserted.

result = await this.commandService.executeCommand(commandId, object);

So when this ${command:pickRemoteProcess} command is executed, the previous command's value would already be replaced in the configuration passed in since the replacement is done sequentially.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Docker Attach",
            "type": "coreclr",
            "request": "attach",
            "pipeTransport": {
                "pipeProgram": "docker",
                "pipeArgs": [
                    "exec", "-i", "docker-select-value" // Actual value for pickRemoteProcess to use
                ],
                "debuggerPath": "/root/vsdbg/vsdbg",
                "pipeCwd": "${workspaceRoot}",
                "quoteArgs": false
            },
            "processId": "${command:pickRemoteProcess}",
            "sourceFileMap": {
                "/app": "${workspaceRoot}"
            },
            "justMyCode": true
        }
    ]
}

Previously, the object passed into the command execution would be the raw original without replacement values.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Docker Attach",
            "type": "coreclr",
            "request": "attach",
            "pipeTransport": {
                "pipeProgram": "docker",
                "pipeArgs": [
                    "exec", "-i", "${command:vscode-docker.containers.select}" // Value is known in the array, but not replaced till after all other commands are executed.
                ],
                "debuggerPath": "/root/vsdbg/vsdbg",
                "pipeCwd": "${workspaceRoot}",
                "quoteArgs": false
            },
            "processId": "${command:pickRemoteProcess}",
            "sourceFileMap": {
                "/app": "${workspaceRoot}"
            },
            "justMyCode": true
        }
    ]
}

As for documentation updates, I do not think any updates are needed; as the current documentation makes it sound like how it works with my changes is how it should work.
https://code.visualstudio.com/docs/editor/variables-reference#_command-variables

When a command variable is interpolated, the command is run and the variable is substituted by the command's (string) result.

Please let me know if I have missed something or need to update anything else.

const variableValues: IStringDictionary<string> = Object.create(null);

for (const variable of variables) {
const config = deepClone(configuration);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make a clone of the configuration so we do not manipulate the object passed into this function.

@@ -184,7 +182,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR
case 'command':
// use the name as a command ID #12735
const commandId = (variableToCommandMap ? variableToCommandMap[name] : undefined) || name;
result = await this.commandService.executeCommand(commandId, configuration);
result = await this.commandService.executeCommand(commandId, object);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The object passed into executeCommand now has all the previously evaluated replacements inserted.

variables.push(command);
const found = command in variables;
if (!found) {
// NOTE this if assumes that the user will only ever want one computed value. (e.g. have two of the same command but only get the first output for both)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumption was from the existing code. Just added a comment to make it clear while I was making changes.

@davidruhmann
Copy link
Author

@weinand
Interesting point that I had forgotten about on the json ordering non-guarantee. Looking at some different ways to resolve that. Now that you mention it, I think I remember seeing some discussion on ordering of variables/commands from a while back in an issue. Going to see if I can find the discussion...

Also have some ideas on how to resolve the ordering that I will play with. Do you have any specific thoughts around it?

Some of my initial thoughts:

  • Order by nested level. Guarantee variables in a nested level object are resolved before the parent variables. This would not guarantee ordering of variables at the same level. This would just be an initial solution that requires no user changes.
  • Add ordering notation to the variables (bigger change). (Think this is what the discussion I am trying to find was about)

@weinand
Copy link
Contributor

weinand commented Mar 16, 2020

@davidruhmann I've reopened issue #89758

Let's continue the discussion there and please verify that my take of the problem is correct.

@weinand
Copy link
Contributor

weinand commented Nov 4, 2020

@davidruhmann Thanks a lot for the PR, but we do not plan to solve #89758 on the VS Code side. Please see my comment

@weinand weinand closed this Nov 4, 2020
@github-actions github-actions bot locked and limited conversation to collaborators Dec 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
debug Debug viewlet, configurations, breakpoints, adapter issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pipeTransport.pipeArgs command variable replacement not working
2 participants