From 0e2c893269178baceb9c329080894b894aa5c1f5 Mon Sep 17 00:00:00 2001 From: Bruce Payette Date: Thu, 16 Aug 2018 17:42:09 -0700 Subject: [PATCH 1/3] Added LocationChangedAction handler + tests --- .../engine/MshCmdlet.cs | 5 +++ .../engine/SessionStateLocationAPIs.cs | 41 +++++++++++++++++++ .../Set-Location.Tests.ps1 | 36 ++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/src/System.Management.Automation/engine/MshCmdlet.cs b/src/System.Management.Automation/engine/MshCmdlet.cs index f421923527d..2736135c5de 100644 --- a/src/System.Management.Automation/engine/MshCmdlet.cs +++ b/src/System.Management.Automation/engine/MshCmdlet.cs @@ -356,6 +356,11 @@ public CommandInfo GetCommand(string commandName, CommandTypes type, object[] ar /// public System.EventHandler PostCommandLookupAction { get; set; } + /// + /// This action is invoked everytime the runspace location (cwd) is changed. + /// + public System.EventHandler LocationChangedAction { get; set; } + /// /// Returns the CmdletInfo object that corresponds to the name argument /// diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index 479186d9c62..50d8195b04c 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -200,6 +200,7 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) throw PSTraceSource.NewArgumentNullException("path"); } + PathInfo current = CurrentLocation; string originalPath = path; string driveName = null; ProviderInfo provider = null; @@ -553,6 +554,15 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) // Set the $PWD variable to the new location this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal); + + // If an action has been defined for location changes, invoke it now. + if (PublicSessionState.InvokeCommand.LocationChangedAction != null) + { + var eventArgs = new LocationChangedEventArgs(PublicSessionState, current, CurrentLocation); + PublicSessionState.InvokeCommand.LocationChangedAction.Invoke(ExecutionContext.CurrentRunspace, eventArgs); + s_tracer.WriteLine("Invoked LocationChangedAction"); + } + return this.CurrentLocation; } // SetLocation @@ -1046,5 +1056,36 @@ internal PathInfoStack SetDefaultLocationStack(string stackName) #endregion push-Pop current working directory } // SessionStateInternal class + + /// + /// Arguments for the LocationChangedEvent + /// + public class LocationChangedEventArgs : EventArgs + { + /// + /// Construct an instance of this object. + /// + public LocationChangedEventArgs(SessionState sessionState, PathInfo oldPath, PathInfo newPath) + { + SessionState = sessionState; + OldPath = oldPath; + NewPath = newPath; + } + + /// + /// The path we changed from + /// + public PathInfo OldPath { get; internal set;} + + /// + /// The path we changed to. + /// + public PathInfo NewPath { get; internal set;} + + /// + /// The session state instance for the current runspace. + /// + public SessionState SessionState {get; internal set; } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 95680dbe068..9aca5fef966 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -144,4 +144,40 @@ Describe "Set-Location" -Tags "CI" { { Set-Location - } | Should -Throw -ErrorId 'System.InvalidOperationException,Microsoft.PowerShell.Commands.SetLocationCommand' } } + + Context 'Test the LocationChangedAction event handler' { + + AfterEach { + $ExecutionContext.InvokeCommand.LocationChangedAction = $null + } + + It 'The LocationChangedAction should fire when changing location' { + $initialPath = $pwd + $oldPath = $null + $newPath = $null + $eventSessionState = $null + $eventRunspace = $null + $ExecutionContext.InvokeCommand.LocationChangedAction = { + (Get-Variable eventRunspace).Value = $this + (Get-Variable eventSessionState).Value = $_.SessionState + (Get-Variable oldPath).Value = $_.oldPath + (Get-Variable newPath).Value = $_.newPath + } + Set-Location .. + $newPath.Path | Should Be $pwd.Path + $oldPath.Path | Should Be $initialPath.Path + $eventSessionState | Should Be $ExecutionContext.SessionState + $eventRunspace | Should Be ([runspace]::DefaultRunspace) + } + + It 'Errors in the LocationChangedAction should be catchable but not fail the cd' { + $location = $PWD + Set-Location .. + $ExecutionContext.InvokeCommand.LocationChangedAction = { throw "Boom" } + # Verify that the exception occurred + { Set-Location $location } | Should Throw "Boom" + # But the location should still have changed + $PWD.Path | Should Be $location.Path + } + } } From 61e7287ebe63a3bcca1694b58ac87a08afef8469 Mon Sep 17 00:00:00 2001 From: Bruce Payette Date: Fri, 17 Aug 2018 14:44:47 -0700 Subject: [PATCH 2/3] CodeFactor changes (doc comments mostly); changed 'Should Be' to 'Should -Be' in the tests. --- .../engine/MshCmdlet.cs | 6 +-- .../engine/SessionStateLocationAPIs.cs | 49 ++++++++++++------- .../Set-Location.Tests.ps1 | 10 ++-- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/System.Management.Automation/engine/MshCmdlet.cs b/src/System.Management.Automation/engine/MshCmdlet.cs index 2736135c5de..12979eaf956 100644 --- a/src/System.Management.Automation/engine/MshCmdlet.cs +++ b/src/System.Management.Automation/engine/MshCmdlet.cs @@ -356,9 +356,9 @@ public CommandInfo GetCommand(string commandName, CommandTypes type, object[] ar /// public System.EventHandler PostCommandLookupAction { get; set; } - /// - /// This action is invoked everytime the runspace location (cwd) is changed. - /// + /// + /// Gets or sets the action that is invoked everytime the runspace location (cwd) is changed. + /// public System.EventHandler LocationChangedAction { get; set; } /// diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index 50d8195b04c..c1d0db10be8 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -1057,35 +1057,46 @@ internal PathInfoStack SetDefaultLocationStack(string stackName) #endregion push-Pop current working directory } // SessionStateInternal class - /// - /// Arguments for the LocationChangedEvent - /// + /// + /// Event argument for the LocationChangedAction containing + /// information about the old location we were in and the new + /// location we changed to. + /// public class LocationChangedEventArgs : EventArgs { - /// - /// Construct an instance of this object. - /// - public LocationChangedEventArgs(SessionState sessionState, PathInfo oldPath, PathInfo newPath) + /// + /// Initializes a new instance of the LocationChangedEventArgs class. + /// + /// + /// The public session state instance associated with this runspace. + /// + /// + /// The path we changed locations from. + /// + /// + /// The path we change locations to. + /// + internal LocationChangedEventArgs(SessionState sessionState, PathInfo oldPath, PathInfo newPath) { SessionState = sessionState; OldPath = oldPath; NewPath = newPath; } - /// - /// The path we changed from - /// - public PathInfo OldPath { get; internal set;} + /// + /// Gets the path we changed location from. + /// + public PathInfo OldPath { get; internal set; } - /// - /// The path we changed to. - /// - public PathInfo NewPath { get; internal set;} + /// + /// Gets the path we changed location to. + /// + public PathInfo NewPath { get; internal set; } - /// - /// The session state instance for the current runspace. - /// - public SessionState SessionState {get; internal set; } + /// + /// Gets the session state instance for the current runspace. + /// + public SessionState SessionState { get; internal set; } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 9aca5fef966..5ea2f278bc7 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -164,10 +164,10 @@ Describe "Set-Location" -Tags "CI" { (Get-Variable newPath).Value = $_.newPath } Set-Location .. - $newPath.Path | Should Be $pwd.Path - $oldPath.Path | Should Be $initialPath.Path - $eventSessionState | Should Be $ExecutionContext.SessionState - $eventRunspace | Should Be ([runspace]::DefaultRunspace) + $newPath.Path | Should -Be $pwd.Path + $oldPath.Path | Should -Be $initialPath.Path + $eventSessionState | Should -Be $ExecutionContext.SessionState + $eventRunspace | Should -Be ([runspace]::DefaultRunspace) } It 'Errors in the LocationChangedAction should be catchable but not fail the cd' { @@ -177,7 +177,7 @@ Describe "Set-Location" -Tags "CI" { # Verify that the exception occurred { Set-Location $location } | Should Throw "Boom" # But the location should still have changed - $PWD.Path | Should Be $location.Path + $PWD.Path | Should -Be $location.Path } } } From d1b62f5b9df26dd06e3cca3fd4bbe5d424bb2ff5 Mon Sep 17 00:00:00 2001 From: Bruce Payette Date: Fri, 17 Aug 2018 16:24:11 -0700 Subject: [PATCH 3/3] more 'bad spacing in comments' code factor fixes --- .../engine/SessionStateLocationAPIs.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index c1d0db10be8..2112f57767f 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -1065,17 +1065,17 @@ internal PathInfoStack SetDefaultLocationStack(string stackName) public class LocationChangedEventArgs : EventArgs { /// - /// Initializes a new instance of the LocationChangedEventArgs class. + /// Initializes a new instance of the LocationChangedEventArgs class. /// /// /// The public session state instance associated with this runspace. - /// + /// /// /// The path we changed locations from. - /// + /// /// /// The path we change locations to. - /// + /// internal LocationChangedEventArgs(SessionState sessionState, PathInfo oldPath, PathInfo newPath) { SessionState = sessionState;