Files
PowerShell-PowerShell/src/System.Management.Automation/engine/SessionStateScopeAPIs.cs
T
PowerShell Team 60b3b304f2 Move files from psl-monad submodule to super-project
This commit uses psl-monad branch source-depot 7209cb9
And corresponds to [SD:688741]
2016-03-30 17:16:23 -07:00

342 lines
12 KiB
C#

/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Threading;
using Dbg=System.Management.Automation;
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56500
namespace System.Management.Automation
{
/// <summary>
/// Holds the state of a Monad Shell session
/// </summary>
internal sealed partial class SessionStateInternal
{
/// <summary>
/// The current scope. It is either the global scope or
/// a nested scope within the global scope. The current
/// scope is implied or can be accessed using $local in
/// the shell.
/// </summary>
private SessionStateScope currentScope;
/// <summary>
/// Given a scope identifier, returns the proper session state scope.
/// </summary>
///
/// <param name="scopeID">
/// A scope identifier that is either one of the "special" scopes like
/// "global", "local", or "private, or a numeric ID of a relative scope
/// to the current scope.
/// </param>
///
/// <returns>
/// The scope identified by the scope ID or the current scope if the
/// scope ID is not defined as a special or numeric scope identifier.
/// </returns>
///
/// <exception cref="ArgumentException">
/// If <paramref name="scopeID"/> is less than zero, or not
/// a number and not "script", "global", "local", or "private"
/// </exception>
///
/// <exception cref="ArgumentOutOfRangeException">
/// If <paramref name="scopeID"/> is less than zero or greater than the number of currently
/// active scopes.
/// </exception>
///
internal SessionStateScope GetScopeByID(string scopeID)
{
SessionStateScope result = currentScope;
if (!string.IsNullOrEmpty(scopeID))
{
if (String.Equals(
scopeID,
StringLiterals.Global,
StringComparison.OrdinalIgnoreCase))
{
result = _globalScope;
}
else if (String.Equals(
scopeID,
StringLiterals.Local,
StringComparison.OrdinalIgnoreCase))
{
result = currentScope;
}
else if (String.Equals(
scopeID,
StringLiterals.Private,
StringComparison.OrdinalIgnoreCase))
{
result = currentScope;
}
else if (String.Equals(
scopeID,
StringLiterals.Script,
StringComparison.OrdinalIgnoreCase))
{
// Get the current script scope from the stack.
result = currentScope.ScriptScope;
}
else
{
// Since the scope is not any of the special scopes
// try parsing it as an ID
try
{
int scopeNumericID = Int32.Parse(scopeID, System.Globalization.CultureInfo.CurrentCulture);
if (scopeNumericID < 0)
{
throw PSTraceSource.NewArgumentOutOfRangeException("scopeID", scopeID);
}
result = GetScopeByID(scopeNumericID) ?? currentScope;
}
catch (FormatException)
{
throw PSTraceSource.NewArgumentException("scopeID", AutomationExceptions.InvalidScopeIdArgument, "scopeID");
}
catch (OverflowException)
{
throw PSTraceSource.NewArgumentOutOfRangeException("scopeID", scopeID);
}
}
}
return result;
} // GetScopeByID
/// <summary>
/// Given a scope ID, walks the scope list to the appropriate scope and returns it.
/// </summary>
///
/// <param name="scopeID">
/// The numeric indexer to the scope relative to the current scope.
/// </param>
///
/// <returns>
/// The scope at the index specified. The index is relative to the current
/// scope.
/// </returns>
///
/// <exception cref="ArgumentOutOfRangeException">
/// If <paramref name="scopeID"/> is less than zero or greater than the number of currently
/// active scopes.
/// </exception>
///
internal SessionStateScope GetScopeByID(int scopeID)
{
SessionStateScope processingScope = currentScope;
int originalID = scopeID;
while (scopeID > 0 && processingScope != null)
{
processingScope = processingScope.Parent;
scopeID--;
}
if (processingScope == null && scopeID >= 0)
{
ArgumentOutOfRangeException outOfRange =
PSTraceSource.NewArgumentOutOfRangeException(
"scopeID",
originalID,
SessionStateStrings.ScopeIDExceedsAvailableScopes,
originalID);
throw outOfRange;
}
return processingScope;
} // GetScopeByID
/// <summary>
/// The global scope of session state. Can be accessed
/// using $global in the shell.
/// </summary>
internal SessionStateScope GlobalScope { get { return _globalScope; } }
private readonly SessionStateScope _globalScope;
/// <summary>
/// The module scope of a session state. This is only used internally
/// by the engine. There is no module scope qualifier.
/// </summary>
internal SessionStateScope ModuleScope { get { return _moduleScope; } }
private readonly SessionStateScope _moduleScope;
/// <summary>
/// Gets the session state current scope.
/// </summary>
internal SessionStateScope CurrentScope
{
get
{
return currentScope;
}
set
{
Diagnostics.Assert(
value != null,
"A null scope should never be set");
#if DEBUG
// This code is ifdef'd for DEBUG because it may pose a significant
// performance hit and is only really required to validate our internal
// code. There is no way anyone outside the Monad codebase can cause
// these error conditions to be hit.
// Need to make sure the new scope is in the global scope lineage
SessionStateScope scope = value;
bool inGlobalScopeLineage = false;
while (scope != null)
{
if (scope == _globalScope)
{
inGlobalScopeLineage = true;
break;
}
scope = scope.Parent;
}
Diagnostics.Assert(
inGlobalScopeLineage,
"The scope specified to be set in CurrentScope is not in the global scope lineage. All scopes must originate from the global scope.");
#endif
currentScope = value;
}
} // CurrentScope
/// <summary>
/// Gets the session state current script scope.
/// </summary>
internal SessionStateScope ScriptScope { get { return currentScope.ScriptScope; } }
/// <summary>
/// Creates a new scope in the scope tree and assigns the parent
/// and child scopes appropriately.
/// </summary>
///
/// <param name="isScriptScope">
/// If true, the new scope is pushed on to the script scope stack and
/// can be referenced using $script:
/// </param>
///
/// <returns>
/// A new SessionStateScope which is a child of the current scope.
/// </returns>
///
internal SessionStateScope NewScope(bool isScriptScope)
{
Diagnostics.Assert(
currentScope != null,
"The currentScope should always be set.");
// Create the new child scope.
SessionStateScope newScope = new SessionStateScope(currentScope);
if (isScriptScope)
{
newScope.ScriptScope = newScope;
}
return newScope;
} // NewScope
/// <summary>
/// Removes the current scope from the scope tree and
/// changes the current scope to the parent scope.
/// </summary>
///
/// <param name="scope">
/// The scope to cleanup and remove.
/// </param>
///
/// <exception cref="SessionStateUnauthorizedAccessException">
/// The global scope cannot be removed.
/// </exception>
///
internal void RemoveScope(SessionStateScope scope)
{
Diagnostics.Assert(
currentScope != null,
"The currentScope should always be set.");
if (scope == _globalScope)
{
SessionStateUnauthorizedAccessException e =
new SessionStateUnauthorizedAccessException(
StringLiterals.Global,
SessionStateCategory.Scope,
"GlobalScopeCannotRemove",
SessionStateStrings.GlobalScopeCannotRemove);
throw e;
}
// Give the provider a chance to cleanup the drive data associated
// with drives in this scope
foreach (PSDriveInfo drive in scope.Drives)
{
if (drive == null)
{
continue;
}
CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);
// Call CanRemoveDrive to give the provider a chance to cleanup
// but ignore the return value and exceptions
try
{
CanRemoveDrive(drive, context);
}
catch (LoopFlowException)
{
throw;
}
catch (PipelineStoppedException)
{
throw;
}
catch (ActionPreferenceStopException)
{
throw;
}
catch (Exception e) // Catch-all OK, 3rd party callout.
{
CommandProcessorBase.CheckForSevereException(e);
// Ignore all exceptions from the provider as we are
// going to force the removal anyway
}
} // foreach drive
scope.RemoveAllDrives();
// If the scope being removed is the current scope,
// then it must be removed from the tree.
if (scope == currentScope && currentScope.Parent != null)
{
currentScope = currentScope.Parent;
}
scope.Parent = null;
} // RemoveScope
} // SessionStateInternal class
}
#pragma warning restore 56500