Skip to content
Permalink
Browse files

Consume Editor Services host as PowerShell module

This change refactors the existing PowerShell Editor Services host
management and editor client code to use the PSES host as a PowerShell
module rather than its previous executable form.  This involves launching
the powershell.exe process and loading up the PSES host as a module in
that process.  It also involves communicating with the PSES host via named
pipes instead of standard in/out as we did previously.

This change can be understood further by looking at the following pull
request at the PowerShellEditorServices repo:

PowerShell/PowerShellEditorServices#256
  • Loading branch information...
daviwil committed May 16, 2016
1 parent 2e9b339 commit e22921df7899429f815919a595e670bb010ee2c0
Showing with 338 additions and 162 deletions.
  1. +3 −0 .gitignore
  2. +2 −0 .vscodeignore
  3. +8 −0 modules/README.md
  4. +5 −78 package.json
  5. +67 −0 scripts/Start-EditorServices.ps1
  6. +53 −0 src/debugAdapter.ts
  7. +19 −0 src/logging.ts
  8. +177 −82 src/main.ts
  9. +4 −2 src/settings.ts
@@ -3,6 +3,9 @@ examples/Release/
examples/Tests/foo*.txt
out/
node_modules/
logs/
modules/*
!modules/README.md
vscode-powershell.zip
vscps-preview.zip
*.vsix
@@ -7,3 +7,5 @@ build/**
bin/EditorServices.log
bin/DebugAdapter.log
bin/*.vshost.*
logs/

@@ -0,0 +1,8 @@
## `modules` folder README

This folder contains modules that are bundled with the vscode-powershell extension.
All subfolders are not included in our GitHub repository, they are added here just
before the module is published to the Visual Studio Marketplace.

This file serves as a placeholder so that the `modules` folder will be included
in our Git repository.
@@ -118,19 +118,8 @@
"powershell"
]
},
"windows": {
"program": "bin/Microsoft.PowerShell.EditorServices.Host.exe"
},
"winx86": {
"program": "bin/Microsoft.PowerShell.EditorServices.Host.x86.exe"
},
"args": [
"/debugAdapter",
"/logLevel:Verbose",
"/hostName:\"Visual Studio Code Host\"",
"/hostProfileId:Microsoft.VSCode",
"/hostVersion:0.6.1"
],
"program": "./out/debugAdapter.js",
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [
@@ -165,68 +154,6 @@
"program": "${file}",
"args": [],
"cwd": "${file}"
},
{
"name": "PowerShell x86",
"type": "PowerShell x86",
"request": "launch",
"program": "${file}",
"args": [],
"cwd": "${file}"
}
]
},
{
"type": "PowerShell x86",
"enableBreakpointsFor": {
"languageIds": [
"powershell"
]
},
"windows": {
"program": "bin/Microsoft.PowerShell.EditorServices.Host.x86.exe"
},
"args": [
"/debugAdapter",
"/logLevel:Verbose",
"/hostName:\"Visual Studio Code Host\"",
"/hostProfileId:Microsoft.VSCode",
"/hostVersion:0.6.1"
],
"configurationAttributes": {
"launch": {
"required": [
"program"
],
"properties": {
"program": {
"type": "string",
"description": "Absolute path to the PowerShell script to launch under the debugger."
},
"args": {
"type": "array",
"description": "Command line arguments to pass to the PowerShell script.",
"items": {
"type": "string"
},
"default": []
},
"cwd": {
"type": "string",
"description": "Absolute path to the working directory. Default is the current workspace.",
"default": "."
}
}
}
},
"initialConfigurations": [
{
"name": "PowerShell x86",
"type": "PowerShell x86",
"request": "launch",
"program": "${file}",
"args": [],
"cwd": "${file}"
}
]
}
@@ -255,10 +182,10 @@
"default": "",
"description": "Specifies the path to a PowerShell Script Analyzer settings file. Use either an absolute path (to override the default settings for all projects) or use a path relative to your workspace."
},
"powershell.developer.editorServicesHostPath": {
"powershell.developer.bundledModulesPath": {
"type": "string",
"default": "../bin/",
"description": "Specifies the path to the folder containing the PowerShell Editor Services host executables."
"default": "../modules/",
"description": "Specifies the path to the folder containing modules that are bundled with the PowerShell extension (i.e. PowerShell Editor Services, PowerShell Script Analyzer, Plaster)"
},
"powershell.developer.editorServicesLogLevel": {
"type": "string",
@@ -0,0 +1,67 @@
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$EditorServicesVersion,

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$HostName,

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$HostProfileId,

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$HostVersion,

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$LanguageServicePipeName,

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]
$DebugServicePipeName,

[ValidateNotNullOrEmpty()]
[string]
$BundledModulesPath,

[ValidateNotNullOrEmpty()]
$LogPath,

[ValidateSet("Normal", "Verbose", "Error")]
$LogLevel,

[switch]
$WaitForCompletion,

[switch]
$WaitForDebugger
)

# Add BundledModulesPath to $env:PSModulePath
if ($BundledModulesPath) {
$env:PSModulePath = $BundledModulesPath + ";" + $env:PSModulePath
}

$parsedVersion = [System.Version]::new($EditorServicesVersion)
Import-Module PowerShellEditorServices -RequiredVersion $parsedVersion -ErrorAction Stop

Start-EditorServicesHost `
-HostName $HostName `
-HostProfileId $HostProfileId `
-HostVersion $HostVersion `
-LogPath $LogPath `
-LogLevel $LogLevel `
-LanguageServicePipeName $LanguageServicePipeName `
-DebugServicePipeName $DebugServicePipeName `
-BundledModulesPath $BundledModulesPath `
-WaitForCompletion:$WaitForCompletion.IsPresent `
-WaitForDebugger:$WaitForDebugger.IsPresent
@@ -0,0 +1,53 @@
import fs = require('fs');
import path = require('path');
import net = require('net');
import logging = require('./logging');

// NOTE: The purpose of this file is to serve as a bridge between
// VS Code's debug adapter client (which communicates via stdio) and
// PowerShell Editor Services' debug service (which communicates via
// named pipes or a network protocol). It is purely a naive data
// relay between the two transports.

var logBasePath = path.resolve(__dirname, "../logs");
logging.ensurePathExists(logBasePath);

var debugAdapterLogWriter =
fs.createWriteStream(
path.resolve(
logBasePath,
logging.getLogName("DebugAdapterClient")));

// Pause the stdin buffer until we're connected to the
// debug server
process.stdin.pause();

// Establish connection before setting up the session
let pipeName = "\\\\.\\pipe\\PSES-VSCode-DebugService-" + process.env.VSCODE_PID;
debugAdapterLogWriter.write("Connecting to named pipe: " + pipeName + "\r\n");
let debugServiceSocket = net.connect(pipeName);

// Write any errors to the log file
debugServiceSocket.on(
'error',
(e) => debugAdapterLogWriter.write("Named pipe ERROR: " + e + "\r\n"));

// Route any output from the socket through stdout
debugServiceSocket.on(
'data',
(data: Buffer) => process.stdout.write(data));

// Wait for the connection to complete
debugServiceSocket.on(
'connect',
() => {
debugAdapterLogWriter.write("Connected to named pipe: " + pipeName + "\r\n");

// When data comes on stdin, route it through the socket
process.stdin.on(
'data',
(data: Buffer) => debugServiceSocket.write(data));

// Resume the stdin stream
process.stdin.resume();
});
@@ -0,0 +1,19 @@
import fs = require('fs');

export function ensurePathExists(targetPath: string) {
// Ensure that the path exists
try {
fs.mkdirSync(targetPath);
}
catch (e) {
// If the exception isn't to indicate that the folder
// exists already, rethrow it.
if (e.code != 'EEXIST') {
throw e;
}
}
}

export function getLogName(baseName: string): string {
return Math.floor(Date.now() / 1000) + '-' + baseName + '.log';
}
Oops, something went wrong.

0 comments on commit e22921d

Please sign in to comment.
You can’t perform that action at this time.