Skip to content

Commit

Permalink
Replaced WorkspaceFileSystemWrapper with Get-Content and Get-ChildItem
Browse files Browse the repository at this point in the history
  • Loading branch information
dkattan committed Feb 15, 2024
1 parent e4b2fc4 commit e72a219
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 443 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Task<Unit> Handle(DidChangeWatchedFilesParams request, CancellationToken
string fileContents;
try
{
fileContents = WorkspaceService.ReadFileContents(change.Uri);
fileContents = _workspaceService.ReadFileContents(change.Uri);
}
catch
{
Expand Down

This file was deleted.

137 changes: 87 additions & 50 deletions src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Security;
using System.Text;
using Microsoft.Extensions.FileSystemGlobbing;
using System.Threading;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Services.PowerShell;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Services.Workspace;
using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
Expand Down Expand Up @@ -84,20 +85,23 @@ internal class WorkspaceService
/// </summary>
public bool FollowSymlinks { get; set; }

private readonly IInternalPowerShellExecutionService executionService;

#endregion

#region Constructors

/// <summary>
/// Creates a new instance of the Workspace class.
/// </summary>
public WorkspaceService(ILoggerFactory factory)
public WorkspaceService(ILoggerFactory factory, IInternalPowerShellExecutionService executionService)
{
powerShellVersion = VersionUtils.PSVersion;
logger = factory.CreateLogger<WorkspaceService>();
WorkspaceFolders = new List<WorkspaceFolder>();
ExcludeFilesGlob = new List<string>();
FollowSymlinks = true;
this.executionService = executionService;
}

#endregion
Expand Down Expand Up @@ -139,19 +143,9 @@ public ScriptFile GetFile(DocumentUri documentUri)
// Make sure the file isn't already loaded into the workspace
if (!workspaceFiles.TryGetValue(keyName, out ScriptFile scriptFile))
{
// This method allows FileNotFoundException to bubble up
// if the file isn't found.
using (StreamReader streamReader = OpenStreamReader(documentUri))
{
scriptFile =
new ScriptFile(
documentUri,
streamReader,
powerShellVersion);

workspaceFiles[keyName] = scriptFile;
}

string fileContent = ReadFileContents(documentUri);
scriptFile = new ScriptFile(documentUri, fileContent, powerShellVersion);
workspaceFiles[keyName] = scriptFile;
logger.LogDebug("Opened file on disk: " + documentUri.ToString());
}

Expand Down Expand Up @@ -348,7 +342,6 @@ public IEnumerable<string> EnumeratePSFiles()
ignoreReparsePoints: !FollowSymlinks
);
}

/// <summary>
/// Enumerate all the PowerShell (ps1, psm1, psd1) files in the workspace folders in a
/// recursive manner. Falls back to initial working directory if there are no workspace folders.
Expand All @@ -360,33 +353,22 @@ public IEnumerable<string> EnumeratePSFiles(
int maxDepth,
bool ignoreReparsePoints)
{
Matcher matcher = new();
foreach (string pattern in includeGlobs) { matcher.AddInclude(pattern); }
foreach (string pattern in excludeGlobs) { matcher.AddExclude(pattern); }
PSCommand psCommand = new();
psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Get-ChildItem")
.AddParameter("Path", WorkspacePaths)
.AddParameter("File")
.AddParameter("Recurse")
.AddParameter("ErrorAction", "SilentlyContinue")
.AddParameter("Force")
.AddParameter("Include", includeGlobs.Concat(VersionUtils.IsNetCore ? s_psFileExtensionsCoreFramework : s_psFileExtensionsFullFramework))
.AddParameter("Exclude", excludeGlobs)
.AddParameter("Depth", maxDepth)
.AddParameter("FollowSymlink", !ignoreReparsePoints)
.AddCommand("Select-Object")
.AddParameter("ExpandObject", "FullName");
IEnumerable<string> results = executionService.ExecutePSCommandAsync<string>(psCommand, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
return results;

foreach (string rootPath in WorkspacePaths)
{
if (!Directory.Exists(rootPath))
{
continue;
}

WorkspaceFileSystemWrapperFactory fsFactory = new(
rootPath,
maxDepth,
VersionUtils.IsNetCore ? s_psFileExtensionsCoreFramework : s_psFileExtensionsFullFramework,
ignoreReparsePoints,
logger);

PatternMatchingResult fileMatchResult = matcher.Execute(fsFactory.RootDirectory);
foreach (FilePatternMatch item in fileMatchResult.Files)
{
// item.Path always contains forward slashes in paths when it should be backslashes on Windows.
// Since we're returning strings here, it's important to use the correct directory separator.
string path = VersionUtils.IsWindows ? item.Path.Replace('/', Path.DirectorySeparatorChar) : item.Path;
yield return Path.Combine(rootPath, path);
}
}
}

#endregion
Expand All @@ -403,10 +385,57 @@ internal static StreamReader OpenStreamReader(DocumentUri uri)
return new StreamReader(fileStream, new UTF8Encoding(), detectEncodingFromByteOrderMarks: true);
}

internal static string ReadFileContents(DocumentUri uri)
internal string ReadFileContents(DocumentUri uri)
{
using StreamReader reader = OpenStreamReader(uri);
return reader.ReadToEnd();
PSCommand psCommand = new();
string pspath;
if (uri.Scheme == Uri.UriSchemeFile)
{
pspath = uri.ToUri().LocalPath;
}
else
{
string PSProvider = uri.Authority;
string path = uri.Path;
pspath = $"{PSProvider}::{path}";
}
/* uri - "file:///c:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
* Authority = ""
* Fragment = ""
* Path = "/C:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
* Query = ""
* Scheme = "file"
* PSPath - "Microsoft.PowerShell.Core\FileSystem::C:\Users\dkattan\source\repos\immybot-ref\submodules\PowerShellEditorServices\test\PowerShellEditorServices.Test.Shared\Completion\CompletionExamples.psm1"
*
* Suggested Format:
* Authority = "Microsoft.PowerShell.Core\FileSystem"
* Scheme = "PSProvider"
* Path = "/C:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
* Result -> "PSProvider://Microsoft.PowerShell.Core/FileSystem::C:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
*
* Suggested Format 2:
* Authority = ""
* Scheme = "FileSystem"
* Path = "/C:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
* Result "FileSystem://c:/Users/dkattan/source/repos/immybot-ref/submodules/PowerShellEditorServices/test/PowerShellEditorServices.Test.Shared/Completion/CompletionExamples.psm1"
*/
psCommand.AddCommand("Get-Content")
.AddParameter("LiteralPath", pspath)
.AddParameter("Raw", true)
.AddParameter("ErrorAction", ActionPreference.Stop);
try
{
IEnumerable<string> result = executionService.ExecutePSCommandAsync<string>(psCommand, CancellationToken.None, new PowerShell.Execution.PowerShellExecutionOptions()
{
ThrowOnError = true
}).ConfigureAwait(false).GetAwaiter().GetResult();
return result.FirstOrDefault();
}
catch (ActionPreferenceStopException ex) when (ex.ErrorRecord.CategoryInfo.Category == ErrorCategory.ObjectNotFound && ex.ErrorRecord.TargetObject is string[] missingFiles && missingFiles.Count() == 1)
{
throw new FileNotFoundException(ex.ErrorRecord.ToString(), missingFiles.First(), ex.ErrorRecord.Exception);
}
}

internal string ResolveWorkspacePath(string path) => ResolveRelativeScriptPath(InitialWorkingDirectory, path);
Expand All @@ -429,10 +458,18 @@ internal string ResolveRelativeScriptPath(string baseFilePath, string relativePa
// Get the directory of the original script file, combine it
// with the given path and then resolve the absolute file path.
combinedPath =
Path.GetFullPath(
Path.Combine(
baseFilePath,
relativePath));
Path.GetFullPath(
Path.Combine(
baseFilePath,
relativePath));

PSCommand psCommand = new();
psCommand.AddCommand("Resolve-Path")
.AddParameter("Relative", true)
.AddParameter("Path", relativePath)
.AddParameter("RelativeBasePath", baseFilePath);
IEnumerable<string> result = executionService.ExecutePSCommandAsync<string>(psCommand, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
combinedPath = result.FirstOrDefault();
}
catch (NotSupportedException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public DebugServiceTests()
debugService.DebuggerStopped += OnDebuggerStopped;

// Load the test debug files.
workspace = new WorkspaceService(NullLoggerFactory.Instance);
workspace = new WorkspaceService(NullLoggerFactory.Instance, PsesHostFactory.Create(NullLoggerFactory.Instance));
debugScriptFile = GetDebugScript("DebugTest.ps1");
oddPathScriptFile = GetDebugScript("Debug' W&ith $Params [Test].ps1");
variableScriptFile = GetDebugScript("VariableTest.ps1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class CompletionHandlerTests : IDisposable
public CompletionHandlerTests()
{
psesHost = PsesHostFactory.Create(NullLoggerFactory.Instance);
workspace = new WorkspaceService(NullLoggerFactory.Instance);
workspace = new WorkspaceService(NullLoggerFactory.Instance, psesHost);
completionHandler = new PsesCompletionHandler(NullLoggerFactory.Instance, psesHost, psesHost, workspace);
}

Expand All @@ -42,12 +42,12 @@ public void Dispose()
GC.SuppressFinalize(this);
}

private ScriptFile GetScriptFile(ScriptRegion scriptRegion) => workspace.GetFile(TestUtilities.GetSharedPath(scriptRegion.File));
private async Task<ScriptFile> GetScriptFile(ScriptRegion scriptRegion) => workspace.GetFile(TestUtilities.GetSharedPath(scriptRegion.File));

private Task<CompletionResults> GetCompletionResultsAsync(ScriptRegion scriptRegion)
private async Task<CompletionResults> GetCompletionResultsAsync(ScriptRegion scriptRegion)
{
return completionHandler.GetCompletionsInFileAsync(
GetScriptFile(scriptRegion),
return await completionHandler.GetCompletionsInFileAsync(
await GetScriptFile(scriptRegion),
scriptRegion.StartLineNumber,
scriptRegion.StartColumnNumber,
CancellationToken.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class SymbolsServiceTests : IDisposable
public SymbolsServiceTests()
{
psesHost = PsesHostFactory.Create(NullLoggerFactory.Instance);
workspace = new WorkspaceService(NullLoggerFactory.Instance);
workspace = new WorkspaceService(NullLoggerFactory.Instance, psesHost);
workspace.WorkspaceFolders.Add(new WorkspaceFolder
{
Uri = DocumentUri.FromFileSystemPath(TestUtilities.GetSharedPath("References"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.Symbols;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Test;
using Microsoft.PowerShell.EditorServices.Test.Shared;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Xunit;
Expand All @@ -20,7 +21,7 @@ public class AstOperationsTests

public AstOperationsTests()
{
WorkspaceService workspace = new(NullLoggerFactory.Instance);
WorkspaceService workspace = new(NullLoggerFactory.Instance, PsesHostFactory.Create(NullLoggerFactory.Instance));
scriptFile = workspace.GetFile(TestUtilities.GetSharedPath("References/FunctionReference.ps1"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace PowerShellEditorServices.Test.Services.Symbols
[Trait("Category", "PSScriptAnalyzer")]
public class PSScriptAnalyzerTests
{
private readonly WorkspaceService workspaceService = new(NullLoggerFactory.Instance);
private readonly WorkspaceService workspaceService = new(NullLoggerFactory.Instance, PsesHostFactory.Create(NullLoggerFactory.Instance));
private readonly AnalysisService analysisService;
private const string script = "function Do-Work {}";

Expand Down
5 changes: 3 additions & 2 deletions test/PowerShellEditorServices.Test/Session/WorkspaceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol;
using Microsoft.PowerShell.EditorServices.Test;

namespace PowerShellEditorServices.Test.Session
{
Expand Down Expand Up @@ -39,7 +40,7 @@ public void CanResolveWorkspaceRelativePath()
ScriptFile testPathOutside = CreateScriptFile("c:/Test/PeerPath/FilePath.ps1");
ScriptFile testPathAnotherDrive = CreateScriptFile("z:/TryAndFindMe/FilePath.ps1");

WorkspaceService workspace = new(NullLoggerFactory.Instance);
WorkspaceService workspace = new(NullLoggerFactory.Instance, PsesHostFactory.Create(NullLoggerFactory.Instance));

// Test with zero workspace folders
Assert.Equal(
Expand Down Expand Up @@ -77,7 +78,7 @@ public void CanResolveWorkspaceRelativePath()

internal static WorkspaceService FixturesWorkspace()
{
return new WorkspaceService(NullLoggerFactory.Instance)
return new WorkspaceService(NullLoggerFactory.Instance, PsesHostFactory.Create(NullLoggerFactory.Instance))
{
WorkspaceFolders =
{
Expand Down
22 changes: 4 additions & 18 deletions test/PowerShellEditorServices.Test/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@
"Microsoft.CodeCoverage": "17.8.0"
}
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net462": "1.0.3"
}
},
"Microsoft.PowerShell.5.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.1.0, )",
Expand Down Expand Up @@ -183,11 +174,6 @@
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net462": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "IzAV30z22ESCeQfxP29oVf4qEo8fBGXLXSU6oacv/9Iqe6PzgHDKCaWfwMBak7bSJQM0F5boXWoZS+kChztRIQ=="
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.8.0",
Expand Down Expand Up @@ -550,7 +536,7 @@
"Microsoft.PowerShell.EditorServices.Test.Shared": {
"type": "Project",
"dependencies": {
"Microsoft.PowerShell.EditorServices": "[3.16.0, )"
"Microsoft.PowerShell.EditorServices": "[3.17.0, )"
}
}
},
Expand Down Expand Up @@ -1691,7 +1677,7 @@
"Microsoft.PowerShell.EditorServices.Test.Shared": {
"type": "Project",
"dependencies": {
"Microsoft.PowerShell.EditorServices": "[3.16.0, )"
"Microsoft.PowerShell.EditorServices": "[3.17.0, )"
}
}
},
Expand Down Expand Up @@ -2820,7 +2806,7 @@
"Microsoft.PowerShell.EditorServices.Test.Shared": {
"type": "Project",
"dependencies": {
"Microsoft.PowerShell.EditorServices": "[3.16.0, )"
"Microsoft.PowerShell.EditorServices": "[3.17.0, )"
}
}
},
Expand Down Expand Up @@ -3948,7 +3934,7 @@
"Microsoft.PowerShell.EditorServices.Test.Shared": {
"type": "Project",
"dependencies": {
"Microsoft.PowerShell.EditorServices": "[3.16.0, )"
"Microsoft.PowerShell.EditorServices": "[3.17.0, )"
}
}
}
Expand Down

0 comments on commit e72a219

Please sign in to comment.