Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SubsystemManager.cs310 linesDownload Raw Back to Subsystem
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#nullable enable5 6using System;7using System.Collections.Generic;8using System.Collections.ObjectModel;9using System.Management.Automation.Internal;10using System.Management.Automation.Subsystem.DSC;11using System.Management.Automation.Subsystem.Feedback;12using System.Management.Automation.Subsystem.Prediction;13 14namespace System.Management.Automation.Subsystem15{16    /// <summary>17    /// Class used to manage subsystems.18    /// </summary>19    public static class SubsystemManager20    {21        private static readonly ReadOnlyCollection<SubsystemInfo> s_subsystems;22        private static readonly ReadOnlyDictionary<Type, SubsystemInfo> s_subSystemTypeMap;23        private static readonly ReadOnlyDictionary<SubsystemKind, SubsystemInfo> s_subSystemKindMap;24 25        static SubsystemManager()26        {27            var subsystems = new SubsystemInfo[]28            {29                SubsystemInfo.Create<ICommandPredictor>(30                    SubsystemKind.CommandPredictor,31                    allowUnregistration: true,32                    allowMultipleRegistration: true),33 34                SubsystemInfo.Create<ICrossPlatformDsc>(35                    SubsystemKind.CrossPlatformDsc,36                    allowUnregistration: true,37                    allowMultipleRegistration: false),38 39                SubsystemInfo.Create<IFeedbackProvider>(40                    SubsystemKind.FeedbackProvider,41                    allowUnregistration: true,42                    allowMultipleRegistration: true),43            };44 45            var subSystemTypeMap = new Dictionary<Type, SubsystemInfo>(subsystems.Length);46            var subSystemKindMap = new Dictionary<SubsystemKind, SubsystemInfo>(subsystems.Length);47 48            foreach (var subsystem in subsystems)49            {50                subSystemTypeMap.Add(subsystem.SubsystemType, subsystem);51                subSystemKindMap.Add(subsystem.Kind, subsystem);52            }53 54            s_subsystems = new ReadOnlyCollection<SubsystemInfo>(subsystems);55            s_subSystemTypeMap = new ReadOnlyDictionary<Type, SubsystemInfo>(subSystemTypeMap);56            s_subSystemKindMap = new ReadOnlyDictionary<SubsystemKind, SubsystemInfo>(subSystemKindMap);57 58            // Register built-in suggestion providers.59            RegisterSubsystem(SubsystemKind.FeedbackProvider, new GeneralCommandErrorFeedback());60        }61 62        #region internal - Retrieve subsystem proxy object63 64        /// <summary>65        /// Get the proxy object registered for a specific subsystem.66        /// Return null when the given subsystem is not registered.67        /// </summary>68        /// <remarks>69        /// Design point:70        /// The implementation proxy object is not supposed to expose to users.71        /// Users shouldn't depend on a implementation proxy object directly, but instead should depend on PowerShell APIs.72        /// <para/>73        /// Example: if a user want to use prediction functionality, he/she should use the PowerShell prediction API instead of74        /// directly interacting with the implementation proxy object of `IPrediction`.75        /// </remarks>76        /// <typeparam name="TConcreteSubsystem">The concrete subsystem base type.</typeparam>77        /// <returns>The most recently registered implementation object of the concrete subsystem.</returns>78        internal static TConcreteSubsystem? GetSubsystem<TConcreteSubsystem>()79            where TConcreteSubsystem : class, ISubsystem80        {81            if (s_subSystemTypeMap.TryGetValue(typeof(TConcreteSubsystem), out SubsystemInfo? subsystemInfo))82            {83                var subsystemInfoImpl = (SubsystemInfoImpl<TConcreteSubsystem>)subsystemInfo;84                return subsystemInfoImpl.GetImplementation();85            }86 87            throw new ArgumentException(88                StringUtil.Format(89                    SubsystemStrings.SubsystemTypeUnknown,90                    typeof(TConcreteSubsystem).FullName));91        }92 93        /// <summary>94        /// Get all the proxy objects registered for a specific subsystem.95        /// Return an empty collection when the given subsystem is not registered.96        /// </summary>97        /// <typeparam name="TConcreteSubsystem">The concrete subsystem base type.</typeparam>98        /// <returns>A readonly collection of all implementation objects registered for the concrete subsystem.</returns>99        internal static ReadOnlyCollection<TConcreteSubsystem> GetSubsystems<TConcreteSubsystem>()100            where TConcreteSubsystem : class, ISubsystem101        {102            if (s_subSystemTypeMap.TryGetValue(typeof(TConcreteSubsystem), out SubsystemInfo? subsystemInfo))103            {104                var subsystemInfoImpl = (SubsystemInfoImpl<TConcreteSubsystem>)subsystemInfo;105                return subsystemInfoImpl.GetAllImplementations();106            }107 108            throw new ArgumentException(109                StringUtil.Format(110                    SubsystemStrings.SubsystemTypeUnknown,111                    typeof(TConcreteSubsystem).FullName));112        }113 114        #endregion115 116        #region public - Subsystem metadata117 118        /// <summary>119        /// Get the information about all subsystems.120        /// </summary>121        /// <returns>A readonly collection of all <see cref="SubsystemInfo"/> objects.</returns>122        public static ReadOnlyCollection<SubsystemInfo> GetAllSubsystemInfo()123        {124            return s_subsystems;125        }126 127        /// <summary>128        /// Get the information about a subsystem by the subsystem type.129        /// </summary>130        /// <param name="subsystemType">The base type of a specific concrete subsystem.</param>131        /// <returns>The <see cref="SubsystemInfo"/> object that represents the concrete subsystem.</returns>132        public static SubsystemInfo GetSubsystemInfo(Type subsystemType)133        {134            ArgumentNullException.ThrowIfNull(subsystemType);135 136            if (s_subSystemTypeMap.TryGetValue(subsystemType, out SubsystemInfo? subsystemInfo))137            {138                return subsystemInfo;139            }140 141            throw new ArgumentException(142                subsystemType == typeof(ISubsystem)143                    ? SubsystemStrings.MustUseConcreteSubsystemType144                    : StringUtil.Format(145                        SubsystemStrings.SubsystemTypeUnknown,146                        subsystemType.FullName),147                nameof(subsystemType));148        }149 150        /// <summary>151        /// Get the information about a subsystem by the subsystem kind.152        /// </summary>153        /// <param name="kind">A specific <see cref="SubsystemKind"/>.</param>154        /// <returns>The <see cref="SubsystemInfo"/> object that represents the concrete subsystem.</returns>155        public static SubsystemInfo GetSubsystemInfo(SubsystemKind kind)156        {157            if (s_subSystemKindMap.TryGetValue(kind, out SubsystemInfo? subsystemInfo))158            {159                return subsystemInfo;160            }161 162            throw new ArgumentException(163                StringUtil.Format(164                    SubsystemStrings.SubsystemKindUnknown,165                    kind.ToString()),166                nameof(kind));167        }168 169        #endregion170 171        #region public - Subsystem registration172 173        /// <summary>174        /// Subsystem registration.175        /// </summary>176        /// <typeparam name="TConcreteSubsystem">The concrete subsystem base type.</typeparam>177        /// <typeparam name="TImplementation">The implementation type of that concrete subsystem.</typeparam>178        /// <param name="proxy">An instance of the implementation.</param>179        public static void RegisterSubsystem<TConcreteSubsystem, TImplementation>(TImplementation proxy)180            where TConcreteSubsystem : class, ISubsystem181            where TImplementation : class, TConcreteSubsystem182        {183            ArgumentNullException.ThrowIfNull(proxy);184 185            RegisterSubsystem(GetSubsystemInfo(typeof(TConcreteSubsystem)), proxy);186        }187 188        /// <summary>189        /// Register an implementation for a subsystem.190        /// </summary>191        /// <param name="kind">The target <see cref="SubsystemKind"/> of the registration.</param>192        /// <param name="proxy">An instance of the implementation.</param>193        public static void RegisterSubsystem(SubsystemKind kind, ISubsystem proxy)194        {195            ArgumentNullException.ThrowIfNull(proxy);196 197            SubsystemInfo info = GetSubsystemInfo(kind);198            if (!info.SubsystemType.IsAssignableFrom(proxy.GetType()))199            {200                throw new ArgumentException(201                    StringUtil.Format(202                        SubsystemStrings.ConcreteSubsystemNotImplemented,203                        kind.ToString(),204                        info.SubsystemType.Name),205                    nameof(proxy));206            }207 208            RegisterSubsystem(info, proxy);209        }210 211        private static void RegisterSubsystem(SubsystemInfo subsystemInfo, ISubsystem proxy)212        {213            if (proxy.Id == Guid.Empty)214            {215                throw new ArgumentException(216                    StringUtil.Format(217                        SubsystemStrings.EmptyImplementationId,218                        subsystemInfo.Kind.ToString()),219                    nameof(proxy));220            }221 222            if (string.IsNullOrEmpty(proxy.Name))223            {224                throw new ArgumentException(225                    StringUtil.Format(226                        SubsystemStrings.NullOrEmptyImplementationName,227                        subsystemInfo.Kind.ToString()),228                    nameof(proxy));229            }230 231            if (string.IsNullOrEmpty(proxy.Description))232            {233                throw new ArgumentException(234                    StringUtil.Format(235                        SubsystemStrings.NullOrEmptyImplementationDescription,236                        subsystemInfo.Kind.ToString()),237                    nameof(proxy));238            }239 240            if (subsystemInfo.RequiredCmdlets.Count > 0 || subsystemInfo.RequiredFunctions.Count > 0)241            {242                // Process 'proxy.CmdletImplementationAssembly' and 'proxy.FunctionsToDefine'243                // Functions are added to global scope.244                // Cmdlets are loaded in a way like a snapin, making the 'Source' of the cmdlets to be 'Microsoft.PowerShell.Core'.245                //246                // For example, let's say the Job adapter is made a subsystem, then all `*-Job` cmdlets will be moved out of S.M.A247                // into a subsystem implementation DLL. After registration, all `*-Job` cmdlets should be back in the248                // 'Microsoft.PowerShell.Core' namespace to keep backward compatibility.249                //250                // Both cmdlets and functions are added to the default InitialSessionState used for creating a new Runspace,251                // so the subsystem works for all subsequent new runspaces after it's registered.252                // Take the Job adapter subsystem as an instance again, so when creating another Runspace after the registration,253                // all '*-Job' cmdlets should be available in the 'Microsoft.PowerShell.Core' namespace by default.254            }255 256            subsystemInfo.RegisterImplementation(proxy);257        }258 259        #endregion260 261        #region public - Subsystem unregistration262 263        /// <summary>264        /// Subsystem unregistration.265        /// Throw 'InvalidOperationException' when called for subsystems that cannot be unregistered.266        /// </summary>267        /// <typeparam name="TConcreteSubsystem">The base type of the target concrete subsystem of the un-registration.</typeparam>268        /// <param name="id">The Id of the implementation to be unregistered.</param>269        public static void UnregisterSubsystem<TConcreteSubsystem>(Guid id)270            where TConcreteSubsystem : class, ISubsystem271        {272            UnregisterSubsystem(GetSubsystemInfo(typeof(TConcreteSubsystem)), id);273        }274 275        /// <summary>276        /// Subsystem unregistration.277        /// Throw 'InvalidOperationException' when called for subsystems that cannot be unregistered.278        /// </summary>279        /// <param name="kind">The target <see cref="SubsystemKind"/> of the un-registration.</param>280        /// <param name="id">The Id of the implementation to be unregistered.</param>281        public static void UnregisterSubsystem(SubsystemKind kind, Guid id)282        {283            UnregisterSubsystem(GetSubsystemInfo(kind), id);284        }285 286        private static void UnregisterSubsystem(SubsystemInfo subsystemInfo, Guid id)287        {288            if (subsystemInfo.RequiredCmdlets.Count > 0 || subsystemInfo.RequiredFunctions.Count > 0)289            {290                throw new NotSupportedException("NotSupported yet: unregister subsystem that introduced new cmdlets/functions.");291            }292 293            ISubsystem impl = subsystemInfo.UnregisterImplementation(id);294            if (impl is IDisposable disposable)295            {296                try297                {298                    disposable.Dispose();299                }300                catch301                {302                    // It's OK to ignore all exceptions when disposing the object.303                }304            }305        }306 307        #endregion308    }309}310