/
githubmirror
/
PowerShell
Обзор
Документация
Войти
/
githubmirror
/
PowerShell
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/System.Management.Automation/engine/CommandBase.cs
604 строки
19 KB
Jordan Borean
Add `PipelineStopToken` to `Cmdlet` which will be signaled when the pipeline is stopping (#24620)
25 мар 2025, 00:36
Не верифицирован
25 мар 2025, 00:36
93e053c
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections.ObjectModel; using System.Diagnostics; using System.Management.Automation.Host; using System.Management.Automation.Internal; using System.Management.Automation.Internal.Host; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Threading; namespace System.Management.Automation.Internal { /// <summary> /// Defines members used by Cmdlets. /// All Cmdlets must derive from /// <see cref="System.Management.Automation.Cmdlet"/>. /// </summary> /// <remarks> /// Only use <see cref="System.Management.Automation.Internal.InternalCommand"/> /// as a subclass of /// <see cref="System.Management.Automation.Cmdlet"/>. /// Do not attempt to create instances of /// <see cref="System.Management.Automation.Internal.InternalCommand"/> /// independently, or to derive other classes than /// <see cref="System.Management.Automation.Cmdlet"/> from /// <see cref="System.Management.Automation.Internal.InternalCommand"/>. /// </remarks> /// <seealso cref="System.Management.Automation.Cmdlet"/> /// <!-- /// These are the Cmdlet members which are also used by other /// non-public command types. /// /// Ideally this would be an internal class, but C# does not support /// public classes deriving from internal classes. /// --> [DebuggerDisplay("Command = {_commandInfo}")] public abstract class InternalCommand { #region private_members internal ICommandRuntime commandRuntime; #endregion private_members #region ctor /// <summary> /// Initializes the new instance of Cmdlet class. /// </summary> /// <remarks> /// The only constructor is internal, so outside users cannot create /// an instance of this class. /// </remarks> internal InternalCommand() { this.CommandInfo = null; } #endregion ctor #region internal_members /// <summary> /// Allows you to access the calling token for this command invocation... /// </summary> /// <value></value> internal IScriptExtent InvocationExtent { get; set; } private InvocationInfo _myInvocation = null; /// <summary> /// Return the invocation data object for this command. /// </summary> /// <value>The invocation object for this command.</value> internal InvocationInfo MyInvocation { get { return _myInvocation ??= new InvocationInfo(this); } } /// <summary> /// Represents the current pipeline object under consideration. /// </summary> internal PSObject currentObjectInPipeline = AutomationNull.Value; /// <summary> /// Gets or sets the current pipeline object under consideration. /// </summary> internal PSObject CurrentPipelineObject { get { return currentObjectInPipeline; } set { currentObjectInPipeline = value; } } /// <summary> /// Internal helper. Interface that should be used for interaction with host. /// </summary> internal PSHost PSHostInternal { get { return _CBhost; } } private PSHost _CBhost; /// <summary> /// Internal helper to get to SessionState. /// </summary> internal SessionState InternalState { get { return _state; } } private SessionState _state; /// <summary> /// Internal helper. Indicates whether stop has been requested on this command. /// </summary> internal bool IsStopping { get { MshCommandRuntime mcr = this.commandRuntime as MshCommandRuntime; return (mcr != null && mcr.IsStopping); } } /// <summary> /// Gets the CancellationToken that is signaled when the pipeline is stopping. /// </summary> internal CancellationToken StopToken => commandRuntime is MshCommandRuntime mcr ? mcr.PipelineProcessor.PipelineStopToken : default; /// <summary> /// The information about the command. /// </summary> private CommandInfo _commandInfo; /// <summary> /// Gets or sets the command information for the command. /// </summary> internal CommandInfo CommandInfo { get { return _commandInfo; } set { _commandInfo = value; } } #endregion internal_members #region public_properties /// <summary> /// Gets or sets the execution context. /// </summary> /// <exception cref="System.ArgumentNullException"> /// may not be set to null /// </exception> internal ExecutionContext Context { get { return _context; } set { if (value == null) { throw PSTraceSource.NewArgumentNullException("Context"); } _context = value; Diagnostics.Assert(_context.EngineHostInterface is InternalHost, "context.EngineHostInterface is not an InternalHost"); _CBhost = (InternalHost)_context.EngineHostInterface; // Construct the session state API set from the new context _state = new SessionState(_context.EngineSessionState); } } private ExecutionContext _context; /// <summary> /// This property tells you if you were being invoked inside the runspace or /// if it was an external request. /// </summary> public CommandOrigin CommandOrigin { get { return CommandOriginInternal; } } internal CommandOrigin CommandOriginInternal = CommandOrigin.Internal; #endregion public_properties #region Override /// <summary> /// When overridden in the derived class, performs initialization /// of command execution. /// Default implementation in the base class just returns. /// </summary> internal virtual void DoBeginProcessing() { } /// <summary> /// When overridden in the derived class, performs execution /// of the command. /// </summary> internal virtual void DoProcessRecord() { } /// <summary> /// When overridden in the derived class, performs clean-up /// after the command execution. /// Default implementation in the base class just returns. /// </summary> internal virtual void DoEndProcessing() { } /// <summary> /// When overridden in the derived class, interrupts currently /// running code within the command. It should interrupt BeginProcessing, /// ProcessRecord, and EndProcessing. /// Default implementation in the base class just returns. /// </summary> internal virtual void DoStopProcessing() { } /// <summary> /// When overridden in the derived class, performs clean-up after the command execution. /// </summary> internal virtual void DoCleanResource() { } #endregion Override /// <summary> /// Throws if the pipeline is stopping. /// </summary> /// <exception cref="System.Management.Automation.PipelineStoppedException"></exception> internal void ThrowIfStopping() { if (IsStopping) throw new PipelineStoppedException(); } #region Dispose /// <summary> /// IDisposable implementation /// When the command is complete, release the associated members. /// </summary> /// <remarks> /// Using InternalDispose instead of Dispose pattern because this /// interface was shipped in PowerShell V1 and 3rd cmdlets indirectly /// derive from this interface. If we depend on Dispose() and 3rd /// party cmdlets do not call base.Dispose (which is the case), we /// will still end up having this leak. /// </remarks> internal void InternalDispose(bool isDisposing) { _myInvocation = null; _state = null; _commandInfo = null; _context = null; } #endregion } } namespace System.Management.Automation { #region NativeArgumentPassingStyle /// <summary> /// Defines the different native command argument parsing options. /// </summary> public enum NativeArgumentPassingStyle { /// <summary>Use legacy argument parsing via ProcessStartInfo.Arguments.</summary> Legacy = 0, /// <summary>Use new style argument passing via ProcessStartInfo.ArgumentList.</summary> Standard = 1, /// <summary> /// Use specific to Windows passing style which is Legacy for selected files on Windows, but /// Standard for everything else. This is the default behavior for Windows. /// </summary> Windows = 2 } #endregion NativeArgumentPassingStyle #region ErrorView /// <summary> /// Defines the potential ErrorView options. /// </summary> public enum ErrorView { /// <summary>Existing all red multi-line output.</summary> NormalView = 0, /// <summary>Only show category information.</summary> CategoryView = 1, /// <summary>Concise shows more information on the context of the error or just the message if not a script or parser error.</summary> ConciseView = 2, /// <summary>Detailed will leverage Get-Error to get much more detailed information for the error.</summary> DetailedView = 3, } #endregion ErrorView #region ActionPreference /// <summary> /// Defines the Action Preference options. These options determine /// what will happen when a particular type of event occurs. /// For example, setting shell variable ErrorActionPreference to "Stop" /// will cause the command to stop when an otherwise non-terminating /// error occurs. /// </summary> public enum ActionPreference { /// <summary>Ignore this event and continue</summary> SilentlyContinue = 0, /// <summary>Stop the command</summary> Stop = 1, /// <summary>Handle this event as normal and continue</summary> Continue = 2, /// <summary>Ask whether to stop or continue</summary> Inquire = 3, /// <summary>Ignore the event completely (not even logging it to the target stream)</summary> Ignore = 4, /// <summary>Reserved for future use.</summary> Suspend = 5, /// <summary>Enter the debugger.</summary> Break = 6, } // enum ActionPreference #endregion ActionPreference #region ConfirmImpact /// <summary> /// Defines the ConfirmImpact levels. These levels describe /// the "destructiveness" of an action, and thus the degree of /// important that the user confirm the action. /// For example, setting the read-only flag on a file might be Low, /// and reformatting a disk might be High. /// These levels are also used in $ConfirmPreference to describe /// which operations should be confirmed. Operations with ConfirmImpact /// equal to or greater than $ConfirmPreference are confirmed. /// Operations with ConfirmImpact.None are never confirmed, and /// no operations are confirmed when $ConfirmPreference is ConfirmImpact.None /// (except when explicitly requested with -Confirm). /// </summary> public enum ConfirmImpact { /// <summary>There is never any need to confirm this action.</summary> None, /// <summary> /// This action only needs to be confirmed when the /// user has requested that low-impact changes must be confirmed. /// </summary> Low, /// <summary> /// This action should be confirmed in most scenarios where /// confirmation is requested. /// </summary> Medium, /// <summary> /// This action is potentially highly "destructive" and should be /// confirmed by default unless otherwise specified. /// </summary> High, } #endregion ConfirmImpact /// <summary> /// Defines members and overrides used by Cmdlets. /// All Cmdlets must derive from <see cref="System.Management.Automation.Cmdlet"/>. /// </summary> /// <remarks> /// There are two ways to create a Cmdlet: by deriving from the Cmdlet base class, and by /// deriving from the PSCmdlet base class. The Cmdlet base class is the primary means by /// which users create their own Cmdlets. Extending this class provides support for the most /// common functionality, including object output and record processing. /// If your Cmdlet requires access to the PowerShell Runtime (for example, variables in the session state, /// access to the host, or information about the current Cmdlet Providers,) then you should instead /// derive from the PSCmdlet base class. /// The public members defined by the PSCmdlet class are not designed to be overridden; instead, they /// provided access to different aspects of the PowerShell runtime. /// In both cases, users should first develop and implement an object model to accomplish their /// task, extending the Cmdlet or PSCmdlet classes only as a thin management layer. /// </remarks> /// <seealso cref="System.Management.Automation.Internal.InternalCommand"/> public abstract partial class PSCmdlet : Cmdlet { #region private_members private ProviderIntrinsics _invokeProvider = null; #endregion private_members #region public_properties /// <summary> /// Gets the host interaction APIs. /// </summary> public PSHost Host { get { using (PSTransactionManager.GetEngineProtectionScope()) { return PSHostInternal; } } } /// <summary> /// Gets the instance of session state for the current runspace. /// </summary> public SessionState SessionState { get { using (PSTransactionManager.GetEngineProtectionScope()) { return this.InternalState; } } } /// <summary> /// Gets the event manager for the current runspace. /// </summary> public PSEventManager Events { get { using (PSTransactionManager.GetEngineProtectionScope()) { return this.Context.Events; } } } /// <summary> /// Repository for jobs. /// </summary> public JobRepository JobRepository { get { using (PSTransactionManager.GetEngineProtectionScope()) { return ((LocalRunspace)this.Context.CurrentRunspace).JobRepository; } } } /// <summary> /// Manager for JobSourceAdapters registered. /// </summary> public JobManager JobManager { get { using (PSTransactionManager.GetEngineProtectionScope()) { return ((LocalRunspace)this.Context.CurrentRunspace).JobManager; } } } /// <summary> /// Repository for runspaces. /// </summary> internal RunspaceRepository RunspaceRepository { get { return ((LocalRunspace)this.Context.CurrentRunspace).RunspaceRepository; } } /// <summary> /// Gets the instance of the provider interface APIs for the current runspace. /// </summary> public ProviderIntrinsics InvokeProvider { get { using (PSTransactionManager.GetEngineProtectionScope()) { return _invokeProvider ??= new ProviderIntrinsics(this); } } } #region Provider wrappers /// <Content contentref="System.Management.Automation.PathIntrinsics.CurrentProviderLocation" /> public PathInfo CurrentProviderLocation(string providerId) { using (PSTransactionManager.GetEngineProtectionScope()) { if (providerId == null) { throw PSTraceSource.NewArgumentNullException(nameof(providerId)); } PathInfo result = SessionState.Path.CurrentProviderLocation(providerId); Diagnostics.Assert(result != null, "DataStoreAdapterCollection.GetNamespaceCurrentLocation() should " + "throw an exception, not return null"); return result; } } /// <Content contentref="System.Management.Automation.PathIntrinsics.GetUnresolvedProviderPathFromPSPath" /> public string GetUnresolvedProviderPathFromPSPath(string path) { using (PSTransactionManager.GetEngineProtectionScope()) { return SessionState.Path.GetUnresolvedProviderPathFromPSPath(path); } } /// <Content contentref="System.Management.Automation.PathIntrinsics.GetResolvedProviderPathFromPSPath" /> public Collection<string> GetResolvedProviderPathFromPSPath(string path, out ProviderInfo provider) { using (PSTransactionManager.GetEngineProtectionScope()) { return SessionState.Path.GetResolvedProviderPathFromPSPath(path, out provider); } } #endregion Provider wrappers #endregion internal_members #region ctor /// <summary> /// Initializes the new instance of PSCmdlet class. /// </summary> /// <remarks> /// Only subclasses of <see cref="System.Management.Automation.Cmdlet"/> /// can be created. /// </remarks> protected PSCmdlet() { } #endregion ctor #region public_methods #region PSVariable APIs /// <Content contentref="System.Management.Automation.VariableIntrinsics.GetValue" /> public object GetVariableValue(string name) { using (PSTransactionManager.GetEngineProtectionScope()) { return this.SessionState.PSVariable.GetValue(name); } } /// <Content contentref="System.Management.Automation.VariableIntrinsics.GetValue" /> public object GetVariableValue(string name, object defaultValue) { using (PSTransactionManager.GetEngineProtectionScope()) { return this.SessionState.PSVariable.GetValue(name, defaultValue); } } #endregion PSVariable APIs #region Parameter methods #endregion Parameter methods #endregion public_methods } }