diff --git a/modules.json b/modules.json deleted file mode 100644 index c47939e30a..0000000000 --- a/modules.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "PSScriptAnalyzer":{ - "MinimumVersion":"1.0", - "MaximumVersion":"1.99", - "AllowPrerelease":false - }, - "Plaster":{ - "MinimumVersion":"1.0", - "MaximumVersion":"1.99", - "AllowPrerelease":false - } -} \ No newline at end of file diff --git a/scripts/Start-EditorServices.ps1 b/scripts/Start-EditorServices.ps1 deleted file mode 100644 index a1f9152ab7..0000000000 --- a/scripts/Start-EditorServices.ps1 +++ /dev/null @@ -1,353 +0,0 @@ -# PowerShell Editor Services Bootstrapper Script -# ---------------------------------------------- -# This script contains startup logic for the PowerShell Editor Services -# module when launched by an editor. It handles the following tasks: -# -# - Verifying the existence of dependencies like PowerShellGet -# - Verifying that the expected version of the PowerShellEditorServices module is installed -# - Installing the PowerShellEditorServices module if confirmed by the user -# - Finding unused TCP port numbers for the language and debug services to use -# - Starting the language and debug services from the PowerShellEditorServices module -# -# NOTE: If editor integration authors make modifications to this -# script, please consider contributing changes back to the -# canonical version of this script at the PowerShell Editor -# Services GitHub repository: -# -# https://github.com/PowerShell/PowerShellEditorServices/blob/master/module/Start-EditorServices.ps1 - -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, - - [ValidateNotNullOrEmpty()] - [string] - $BundledModulesPath, - - [ValidateNotNullOrEmpty()] - $LogPath, - - [ValidateSet("Diagnostic", "Normal", "Verbose", "Error", "Diagnostic")] - $LogLevel, - - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] - [string] - $SessionDetailsPath, - - [switch] - $EnableConsoleRepl, - - [switch] - $DebugServiceOnly, - - [string[]] - $AdditionalModules, - - [string[]] - $FeatureFlags, - - [switch] - $WaitForDebugger, - - [switch] - $ConfirmInstall -) - -$minPortNumber = 10000 -$maxPortNumber = 30000 - -if ($LogLevel -eq "Diagnostic") { - $VerbosePreference = 'Continue' - Start-Transcript (Join-Path (Split-Path $LogPath -Parent) Start-EditorServices.log) -Force -} - -function LogSection([string]$msg) { - Write-Verbose "`n#-- $msg $('-' * ([Math]::Max(0, 73 - $msg.Length)))" -} - -function Log([string[]]$msg) { - $msg | Write-Verbose -} - -function ExitWithError($errorString) { - Write-Host -ForegroundColor Red "`n`n$errorString" - - # Sleep for a while to make sure the user has time to see and copy the - # error message - Start-Sleep -Seconds 300 - - exit 1; -} - -# Are we running in PowerShell 2 or earlier? -if ($PSVersionTable.PSVersion.Major -le 2) { - # No ConvertTo-Json on PSv2 and below, so write out the JSON manually - "{`"status`": `"failed`", `"reason`": `"unsupported`", `"powerShellVersion`": `"$($PSVersionTable.PSVersion.ToString())`"}" | - Set-Content -Force -Path "$SessionDetailsPath" -ErrorAction Stop - - ExitWithError "Unsupported PowerShell version $($PSVersionTable.PSVersion), language features are disabled." -} - -function WriteSessionFile($sessionInfo) { - $sessionInfoJson = ConvertTo-Json -InputObject $sessionInfo -Compress - Log "Writing session file with contents:" - Log $sessionInfoJson - $sessionInfoJson | Set-Content -Force -Path "$SessionDetailsPath" -ErrorAction Stop -} - -if ($host.Runspace.LanguageMode -eq 'ConstrainedLanguage') { - WriteSessionFile @{ - "status" = "failed" - "reason" = "languageMode" - "detail" = $host.Runspace.LanguageMode.ToString() - } - - ExitWithError "PowerShell is configured with an unsupported LanguageMode (ConstrainedLanguage), language features are disabled." -} - -# Are we running in PowerShell 5 or later? -$isPS5orLater = $PSVersionTable.PSVersion.Major -ge 5 - -# If PSReadline is present in the session, remove it so that runspace -# management is easier -if ((Get-Module PSReadline).Count -gt 0) { - LogSection "Removing PSReadLine module" - Remove-Module PSReadline -ErrorAction SilentlyContinue -} - -# This variable will be assigned later to contain information about -# what happened while attempting to launch the PowerShell Editor -# Services host -$resultDetails = $null; - -function Test-ModuleAvailable($ModuleName, $ModuleVersion) { - Log "Testing module availability $ModuleName $ModuleVersion" - - $modules = Get-Module -ListAvailable $moduleName - if ($modules -ne $null) { - if ($ModuleVersion -ne $null) { - foreach ($module in $modules) { - if ($module.Version.Equals($moduleVersion)) { - Log "$ModuleName $ModuleVersion found" - return $true; - } - } - } - else { - Log "$ModuleName $ModuleVersion found" - return $true; - } - } - - Log "$ModuleName $ModuleVersion NOT found" - return $false; -} - -function Test-PortAvailability { - param( - [Parameter(Mandatory=$true)] - [int] - $PortNumber - ) - - $portAvailable = $true - - try { - if ($isPS5orLater) { - $ipAddresses = [System.Net.Dns]::GetHostEntryAsync("localhost").Result.AddressList - } - else { - $ipAddresses = [System.Net.Dns]::GetHostEntry("localhost").AddressList - } - - foreach ($ipAddress in $ipAddresses) - { - Log "Testing availability of port ${PortNumber} at address ${ipAddress} / $($ipAddress.AddressFamily)" - - $tcpListener = New-Object System.Net.Sockets.TcpListener @($ipAddress, $PortNumber) - $tcpListener.Start() - $tcpListener.Stop() - } - } - catch [System.Net.Sockets.SocketException] { - $portAvailable = $false - - # Check the SocketErrorCode to see if it's the expected exception - if ($_.Exception.SocketErrorCode -eq [System.Net.Sockets.SocketError]::AddressAlreadyInUse) { - Log "Port $PortNumber is in use." - } - else { - Log "SocketException on port ${PortNumber}: $($_.Exception)" - } - } - - $portAvailable -} - -$portsInUse = @{} -$rand = New-Object System.Random -function Get-AvailablePort() { - $triesRemaining = 10; - - while ($triesRemaining -gt 0) { - do { - $port = $rand.Next($minPortNumber, $maxPortNumber) - } - while ($portsInUse.ContainsKey($port)) - - # Whether we succeed or fail, don't try this port again - $portsInUse[$port] = 1 - - Log "Checking port: $port, attempts remaining $triesRemaining --------------------" - if ((Test-PortAvailability -PortNumber $port) -eq $true) { - Log "Port: $port is available" - return $port - } - - Log "Port: $port is NOT available" - $triesRemaining--; - } - - Log "Did not find any available ports!!" - return $null -} - -# Add BundledModulesPath to $env:PSModulePath -if ($BundledModulesPath) { - $env:PSModulePath = $env:PSModulePath.TrimEnd([System.IO.Path]::PathSeparator) + [System.IO.Path]::PathSeparator + $BundledModulesPath - LogSection "Updated PSModulePath to:" - Log ($env:PSModulePath -split [System.IO.Path]::PathSeparator) -} - -LogSection "Check required modules available" -# Check if PowerShellGet module is available -if ((Test-ModuleAvailable "PowerShellGet") -eq $false) { - Log "Failed to find PowerShellGet module" - # TODO: WRITE ERROR -} - -# Check if the expected version of the PowerShell Editor Services -# module is installed -$parsedVersion = New-Object System.Version @($EditorServicesVersion) -if ((Test-ModuleAvailable "PowerShellEditorServices" $parsedVersion) -eq $false) { - if ($ConfirmInstall -and $isPS5orLater) { - # TODO: Check for error and return failure if necessary - LogSection "Install PowerShellEditorServices" - Install-Module "PowerShellEditorServices" -RequiredVersion $parsedVersion -Confirm - } - else { - # Indicate to the client that the PowerShellEditorServices module - # needs to be installed - Write-Output "needs_install" - } -} - -try { - LogSection "Start up PowerShellEditorServices" - Log "Importing PowerShellEditorServices" - - if ($isPS5orLater) { - Import-Module PowerShellEditorServices -RequiredVersion $parsedVersion -ErrorAction Stop - } - else { - Import-Module PowerShellEditorServices -Version $parsedVersion -ErrorAction Stop - } - - # Locate available port numbers for services - Log "Searching for available socket port for the language service" - $languageServicePort = Get-AvailablePort - - Log "Searching for available socket port for the debug service" - $debugServicePort = Get-AvailablePort - - if (!$languageServicePort -or !$debugServicePort) { - ExitWithError "Failed to find an open socket port for either the language or debug service." - } - - if ($EnableConsoleRepl) { - Write-Host "PowerShell Integrated Console`n" - } - - # Create the Editor Services host - Log "Invoking Start-EditorServicesHost" - $editorServicesHost = - Start-EditorServicesHost ` - -HostName $HostName ` - -HostProfileId $HostProfileId ` - -HostVersion $HostVersion ` - -LogPath $LogPath ` - -LogLevel $LogLevel ` - -AdditionalModules $AdditionalModules ` - -LanguageServicePort $languageServicePort ` - -DebugServicePort $debugServicePort ` - -BundledModulesPath $BundledModulesPath ` - -EnableConsoleRepl:$EnableConsoleRepl.IsPresent ` - -DebugServiceOnly:$DebugServiceOnly.IsPresent ` - -WaitForDebugger:$WaitForDebugger.IsPresent - - # TODO: Verify that the service is started - Log "Start-EditorServicesHost returned $editorServicesHost" - - $resultDetails = @{ - "status" = "started"; - "channel" = "tcp"; - "languageServicePort" = $languageServicePort; - "debugServicePort" = $debugServicePort; - } - - # Notify the client that the services have started - WriteSessionFile $resultDetails - - Log "Wrote out session file" -} -catch [System.Exception] { - $e = $_.Exception; - $errorString = "" - - Log "ERRORS caught starting up EditorServicesHost" - - while ($e -ne $null) { - $errorString = $errorString + ($e.Message + "`r`n" + $e.StackTrace + "`r`n") - $e = $e.InnerException; - Log $errorString - } - - ExitWithError ("An error occurred while starting PowerShell Editor Services:`r`n`r`n" + $errorString) -} - -try { - # Wait for the host to complete execution before exiting - LogSection "Waiting for EditorServicesHost to complete execution" - $editorServicesHost.WaitForCompletion() - Log "EditorServicesHost has completed execution" -} -catch [System.Exception] { - $e = $_.Exception; - $errorString = "" - - Log "ERRORS caught while waiting for EditorServicesHost to complete execution" - - while ($e -ne $null) { - $errorString = $errorString + ($e.Message + "`r`n" + $e.StackTrace + "`r`n") - $e = $e.InnerException; - Log $errorString - } -} diff --git a/src/process.ts b/src/process.ts index da430334ab..ccc1236b7c 100644 --- a/src/process.ts +++ b/src/process.ts @@ -23,6 +23,7 @@ export class PowerShellProcess { constructor( public exePath: string, + private bundledModulesPath: string, private title: string, private log: Logger, private startArgs: string, @@ -40,7 +41,8 @@ export class PowerShellProcess { const startScriptPath = path.resolve( __dirname, - "../../scripts/Start-EditorServices.ps1"); + this.bundledModulesPath, + "PowerShellEditorServices/Start-EditorServices.ps1"); const editorServicesLogPath = this.log.getLogFilePath(logFileName); diff --git a/src/session.ts b/src/session.ts index 9a944292a3..a876f277ff 100644 --- a/src/session.ts +++ b/src/session.ts @@ -53,6 +53,7 @@ export class SessionManager implements Middleware { private languageServerClient: LanguageClient = undefined; private sessionSettings: Settings.ISettings = undefined; private sessionDetails: utils.IEditorServicesSessionDetails; + private bundledModulesPath: string; // When in development mode, VS Code's session ID is a fake // value of "someValue.machineId". Use that to detect dev @@ -144,18 +145,17 @@ export class SessionManager implements Middleware { if (this.powerShellExePath) { - let bundledModulesPath = path.resolve(__dirname, "../../modules"); + this.bundledModulesPath = path.resolve(__dirname, this.sessionSettings.bundledModulesPath); if (this.inDevelopmentMode) { const devBundledModulesPath = path.resolve( __dirname, - this.sessionSettings.developer.bundledModulesPath || - "../../../PowerShellEditorServices/module"); + this.sessionSettings.developer.bundledModulesPath); // Make sure the module's bin path exists if (fs.existsSync(path.join(devBundledModulesPath, "PowerShellEditorServices/bin"))) { - bundledModulesPath = devBundledModulesPath; + this.bundledModulesPath = devBundledModulesPath; } else { this.log.write( "\nWARNING: In development mode but PowerShellEditorServices dev module path cannot be " + @@ -164,12 +164,11 @@ export class SessionManager implements Middleware { } this.editorServicesArgs = - "-EditorServicesVersion '" + this.requiredEditorServicesVersion + "' " + "-HostName 'Visual Studio Code Host' " + "-HostProfileId 'Microsoft.VSCode' " + "-HostVersion '" + this.hostVersion + "' " + "-AdditionalModules @('PowerShellEditorServices.VSCode') " + - "-BundledModulesPath '" + bundledModulesPath + "' " + + "-BundledModulesPath '" + this.bundledModulesPath + "' " + "-EnableConsoleRepl "; if (this.sessionSettings.developer.editorServicesWaitForDebugger) { @@ -179,11 +178,7 @@ export class SessionManager implements Middleware { this.editorServicesArgs += "-LogLevel '" + this.sessionSettings.developer.editorServicesLogLevel + "' "; } - this.startPowerShell( - this.powerShellExePath, - this.sessionSettings.developer.powerShellExeIsWindowsDevBuild, - bundledModulesPath, - this.editorServicesArgs); + this.startPowerShell(); } else { this.setSessionFailure("PowerShell could not be started, click 'Show Logs' for more details."); } @@ -235,6 +230,7 @@ export class SessionManager implements Middleware { this.debugSessionProcess = new PowerShellProcess( this.powerShellExePath, + this.bundledModulesPath, "[TEMP] PowerShell Integrated Console", this.log, this.editorServicesArgs + "-DebugServiceOnly ", @@ -444,11 +440,7 @@ export class SessionManager implements Middleware { ]; } - private startPowerShell( - powerShellExePath: string, - isWindowsDevBuild: boolean, - bundledModulesPath: string, - startArgs: string) { + private startPowerShell() { this.setSessionStatus( "Starting PowerShell...", @@ -461,9 +453,10 @@ export class SessionManager implements Middleware { this.languageServerProcess = new PowerShellProcess( this.powerShellExePath, + this.bundledModulesPath, "PowerShell Integrated Console", this.log, - startArgs, + this.editorServicesArgs, sessionFilePath, this.sessionSettings); diff --git a/src/settings.ts b/src/settings.ts index a9a626562c..85f62b4c4b 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -51,6 +51,7 @@ export interface IDeveloperSettings { export interface ISettings { powerShellExePath?: string; + bundledModulesPath?: string; startAutomatically?: boolean; useX86Host?: boolean; enableProfileLoading?: boolean; @@ -88,7 +89,7 @@ export function load(): ISettings { const defaultDeveloperSettings: IDeveloperSettings = { featureFlags: [], powerShellExePath: undefined, - bundledModulesPath: undefined, + bundledModulesPath: "../../../PowerShellEditorServices/module", editorServicesLogLevel: "Normal", editorServicesWaitForDebugger: false, powerShellExeIsWindowsDevBuild: false, @@ -117,6 +118,8 @@ export function load(): ISettings { configuration.get("startAutomatically", true), powerShellExePath: configuration.get("powerShellExePath", undefined), + bundledModulesPath: + "../../modules", useX86Host: configuration.get("useX86Host", false), enableProfileLoading: @@ -126,7 +129,7 @@ export function load(): ISettings { debugging: configuration.get("debugging", defaultDebuggingSettings), developer: - configuration.get("developer", defaultDeveloperSettings), + getWorkspaceSettingsWithDefaults(configuration, "developer", defaultDeveloperSettings), codeFormatting: configuration.get("codeFormatting", defaultCodeFormattingSettings), integratedConsole: @@ -143,3 +146,18 @@ export function change(settingName: string, newValue: any, global: boolean = fal return configuration.update(settingName, newValue, global); } + +function getWorkspaceSettingsWithDefaults( + workspaceConfiguration: vscode.WorkspaceConfiguration, + settingName: string, + defaultSettings: TSettings): TSettings { + + const importedSettings: TSettings = workspaceConfiguration.get(settingName, defaultSettings); + + for (const setting in importedSettings) { + if (importedSettings[setting]) { + defaultSettings[setting] = importedSettings[setting]; + } + } + return defaultSettings; +} diff --git a/vscode-powershell.build.ps1 b/vscode-powershell.build.ps1 index 99250808e8..c5f03f282f 100644 --- a/vscode-powershell.build.ps1 +++ b/vscode-powershell.build.ps1 @@ -53,7 +53,7 @@ task ResolveEditorServicesPath -Before CleanEditorServices, BuildEditorServices } } -task Restore RestoreNodeModules, RestorePowerShellModules -Before Build +task Restore RestoreNodeModules -Before Build task RestoreNodeModules -If { -not (Test-Path "$PSScriptRoot/node_modules") } { @@ -65,22 +65,9 @@ task RestoreNodeModules -If { -not (Test-Path "$PSScriptRoot/node_modules") } { exec { & npm install $logLevelParam } } -task RestorePowerShellModules -If { -not (Test-Path "$PSScriptRoot/modules/Plaster") } { - $modules = Get-Content -Raw "$PSScriptRoot/modules.json" | ConvertFrom-Json - $modules.PSObject.Properties | ForEach-Object { - $params = @{ - Name = $_.Name - MinimumVersion = $_.Value.MinimumVersion - MaximumVersion = $_.Value.MaximumVersion - AllowPrerelease = $_.Value.AllowPrerelease - Path = "$PSScriptRoot/modules/" - } - Save-Module @params - } -} - task Clean { Write-Host "`n### Cleaning vscode-powershell`n" -ForegroundColor Green + Remove-Item .\modules\* -Exclude "README.md" -Recurse -Force -ErrorAction Ignore Remove-Item .\out -Recurse -Force -ErrorAction Ignore } @@ -122,15 +109,14 @@ task Package { if ($script:psesBuildScriptPath) { Write-Host "`n### Copying PowerShellEditorServices module files" -ForegroundColor Green - Copy-Item -Recurse -Force ..\PowerShellEditorServices\module\PowerShellEditorServices .\modules - Copy-Item -Recurse -Force ..\PowerShellEditorServices\module\PowerShellEditorServices.VSCode .\modules + Copy-Item -Recurse -Force ..\PowerShellEditorServices\module\* .\modules } Write-Host "`n### Packaging PowerShell-insiders.vsix`n" -ForegroundColor Green exec { & node ./node_modules/vsce/out/vsce package } # Change the package to have a static name for automation purposes - Move-Item .\PowerShell-$($script:ExtensionVersion).vsix .\PowerShell-insiders.vsix + Move-Item -Force .\PowerShell-$($script:ExtensionVersion).vsix .\PowerShell-insiders.vsix } task UploadArtifacts -If { $env:AppVeyor } {