Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
DscResourceHelpProvider.cs372 linesDownload Raw Back to help
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics;8using System.IO;9using System.Xml;10 11using Dbg = System.Management.Automation.Diagnostics;12 13namespace System.Management.Automation14{15    internal class DscResourceHelpProvider : HelpProviderWithCache16    {17        /// <summary>18        /// Constructor for DscResourceHelpProvider.19        /// </summary>20        internal DscResourceHelpProvider(HelpSystem helpSystem)21            : base(helpSystem)22        {23            _context = helpSystem.ExecutionContext;24        }25 26        /// <summary>27        /// Execution context of the HelpSystem.28        /// </summary>29        private readonly ExecutionContext _context;30 31        /// <summary>32        /// This is a hashtable to track which help files are loaded already.33        ///34        /// This will avoid one help file getting loaded again and again.35        /// </summary>36        private readonly Hashtable _helpFiles = new Hashtable();37 38        [TraceSource("DscResourceHelpProvider", "DscResourceHelpProvider")]39        private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("DscResourceHelpProvider", "DscResourceHelpProvider");40 41        #region common properties42 43        /// <summary>44        /// Name of the Help Provider.45        /// </summary>46        internal override string Name47        {48            get { return "Dsc Resource Help Provider"; }49        }50 51        /// <summary>52        /// Supported Help Categories.53        /// </summary>54        internal override HelpCategory HelpCategory55        {56            get { return Automation.HelpCategory.DscResource; }57        }58 59        #endregion60 61        /// <summary>62        /// Override SearchHelp to find a dsc resource help matching a pattern.63        /// </summary>64        /// <param name="helpRequest">Help request.</param>65        /// <param name="searchOnlyContent">Not used.</param>66        /// <returns></returns>67        internal override IEnumerable<HelpInfo> SearchHelp(HelpRequest helpRequest, bool searchOnlyContent)68        {69            Debug.Assert(helpRequest != null, "helpRequest cannot be null.");70 71            string target = helpRequest.Target;72            Collection<string> patternList = new Collection<string>();73 74            bool decoratedSearch = !WildcardPattern.ContainsWildcardCharacters(helpRequest.Target);75 76            if (decoratedSearch)77            {78                patternList.Add("*" + target + "*");79            }80            else81                patternList.Add(target);82 83            foreach (string pattern in patternList)84            {85                DscResourceSearcher searcher = new DscResourceSearcher(pattern, _context);86 87                foreach (var helpInfo in GetHelpInfo(searcher))88                {89                    if (helpInfo != null)90                        yield return helpInfo;91                }92            }93        }94 95        /// <summary>96        /// Override ExactMatchHelp to find the matching DscResource matching help request.97        /// </summary>98        /// <param name="helpRequest">Help Request for the search.</param>99        /// <returns>Enumerable of HelpInfo objects.</returns>100        internal override IEnumerable<HelpInfo> ExactMatchHelp(HelpRequest helpRequest)101        {102            Debug.Assert(helpRequest != null, "helpRequest cannot be null.");103 104            if ((helpRequest.HelpCategory & Automation.HelpCategory.DscResource) == 0)105            {106                yield return null;107            }108 109            string target = helpRequest.Target;110 111            DscResourceSearcher searcher = new DscResourceSearcher(target, _context);112 113            foreach (var helpInfo in GetHelpInfo(searcher))114            {115                if (helpInfo != null)116                {117                    yield return helpInfo;118                }119            }120        }121 122        /// <summary>123        /// Get the help in for the DscResource Info.        ///124        /// </summary>125        /// <param name="searcher">Searcher for DscResources.</param>126        /// <returns>Next HelpInfo object.</returns>127        private IEnumerable<HelpInfo> GetHelpInfo(DscResourceSearcher searcher)128        {129            while (searcher.MoveNext())130            {131                DscResourceInfo current = ((IEnumerator<DscResourceInfo>)searcher).Current;132 133                string moduleName = null;134                string moduleDir = current.ParentPath;135 136                // for binary modules, current.Module is empty.137                // in such cases use the leaf folder of ParentPath as filename.138                if (current.Module != null)139                {140                    moduleName = current.Module.Name;141                }142                else if (!string.IsNullOrEmpty(moduleDir))143                {144                    string[] splitPath = moduleDir.Split('\\');145                    moduleName = splitPath[splitPath.Length - 1];146                }147 148                if (!string.IsNullOrEmpty(moduleName) && !string.IsNullOrEmpty(moduleDir))149                {150                    string helpFileToFind = moduleName + "-Help.xml";151 152                    string helpFileName = null;153 154                    Collection<string> searchPaths = new Collection<string>();155                    searchPaths.Add(moduleDir);156 157                    HelpInfo helpInfo = GetHelpInfoFromHelpFile(current, helpFileToFind, searchPaths, true, out helpFileName);158 159                    if (helpInfo != null)160                    {161                        yield return helpInfo;162                    }163                }164            }165        }166 167        /// <summary>168        /// Check whether a HelpItems node indicates that the help content is169        /// authored using maml schema.170        ///171        /// This covers two cases:172        ///     a. If the help file has an extension .maml.173        ///     b. If HelpItems node (which should be the top node of any command help file)174        ///        has an attribute "schema" with value "maml", its content is in maml175        ///        schema.176        /// </summary>177        /// <param name="helpFile">File name.</param>178        /// <param name="helpItemsNode">Nodes to check.</param>179        /// <returns></returns>180        internal static bool IsMamlHelp(string helpFile, XmlNode helpItemsNode)181        {182            Debug.Assert(!string.IsNullOrEmpty(helpFile), "helpFile cannot be null.");183 184            if (helpFile.EndsWith(".maml", StringComparison.OrdinalIgnoreCase))185                return true;186 187            if (helpItemsNode.Attributes == null)188                return false;189 190            foreach (XmlNode attribute in helpItemsNode.Attributes)191            {192                if (attribute.Name.Equals("schema", StringComparison.OrdinalIgnoreCase)193                    && attribute.Value.Equals("maml", StringComparison.OrdinalIgnoreCase))194                {195                    return true;196                }197            }198 199            return false;200        }201 202        #region private methods203 204        private HelpInfo GetHelpInfoFromHelpFile(DscResourceInfo resourceInfo, string helpFileToFind, Collection<string> searchPaths, bool reportErrors, out string helpFile)205        {206            Dbg.Assert(resourceInfo != null, "Caller should verify that resourceInfo != null");207            Dbg.Assert(helpFileToFind != null, "Caller should verify that helpFileToFind != null");208 209            helpFile = MUIFileSearcher.LocateFile(helpFileToFind, searchPaths);210 211            if (!File.Exists(helpFile))212                return null;213 214            if (!string.IsNullOrEmpty(helpFile))215            {216                // Load the help file only once. Then use it from the cache.217                if (!_helpFiles.Contains(helpFile))218                {219                    LoadHelpFile(helpFile, helpFile, resourceInfo.Name, reportErrors);220                }221 222                return GetFromResourceHelpCache(helpFile, Automation.HelpCategory.DscResource);223            }224 225            return null;226        }227 228        /// <summary>229        /// Gets the HelpInfo object corresponding to the command.230        /// </summary>231        /// <param name="helpFileIdentifier">Help file identifier (either name of PSSnapIn or simply full path to help file).</param>232        /// <param name="helpCategory">Help Category for search.</param>233        /// <returns>HelpInfo object.</returns>234        private HelpInfo GetFromResourceHelpCache(string helpFileIdentifier, HelpCategory helpCategory)235        {236            Debug.Assert(!string.IsNullOrEmpty(helpFileIdentifier), "helpFileIdentifier should not be null or empty.");237 238            HelpInfo result = GetCache(helpFileIdentifier);239 240            if (result != null)241            {242                MamlCommandHelpInfo original = (MamlCommandHelpInfo)result;243                result = original.Copy(helpCategory);244            }245 246            return result;247        }248 249        private void LoadHelpFile(string helpFile, string helpFileIdentifier, string commandName, bool reportErrors)250        {251            Exception e = null;252            try253            {254                LoadHelpFile(helpFile, helpFileIdentifier);255            }256            catch (IOException ioException)257            {258                e = ioException;259            }260            catch (System.Security.SecurityException securityException)261            {262                e = securityException;263            }264            catch (XmlException xmlException)265            {266                e = xmlException;267            }268            catch (NotSupportedException notSupportedException)269            {270                e = notSupportedException;271            }272            catch (UnauthorizedAccessException unauthorizedAccessException)273            {274                e = unauthorizedAccessException;275            }276            catch (InvalidOperationException invalidOperationException)277            {278                e = invalidOperationException;279            }280 281            if (e != null)282                s_tracer.WriteLine("Error occurred in DscResourceHelpProvider {0}", e.Message);283 284            if (reportErrors && (e != null))285            {286                ReportHelpFileError(e, commandName, helpFile);287            }288        }289 290        /// <summary>291        /// Load help file for HelpInfo objects. The HelpInfo objects will be292        /// put into help cache.293        /// </summary>294        /// <remarks>295        /// 1. Needs to pay special attention about error handling in this function.296        /// Common errors include: file not found and invalid xml. None of these error297        /// should cause help search to stop.298        /// 2. a helpfile cache is used to avoid same file got loaded again and again.299        /// </remarks>300        private void LoadHelpFile(string helpFile, string helpFileIdentifier)301        {302            Dbg.Assert(!string.IsNullOrEmpty(helpFile), "HelpFile cannot be null or empty.");303            Dbg.Assert(!string.IsNullOrEmpty(helpFileIdentifier), "helpFileIdentifier cannot be null or empty.");304 305            XmlDocument doc = InternalDeserializer.LoadUnsafeXmlDocument(306                new FileInfo(helpFile),307                false, /* ignore whitespace, comments, etc. */308                null); /* default maxCharactersInDocument */309 310            // Add this file into _helpFiles hashtable to prevent it to be loaded again.311            _helpFiles[helpFile] = 0;312 313            XmlNode helpItemsNode = null;314 315            if (doc.HasChildNodes)316            {317                for (int i = 0; i < doc.ChildNodes.Count; i++)318                {319                    XmlNode node = doc.ChildNodes[i];320                    if (node.NodeType == XmlNodeType.Element && string.Equals(node.LocalName, "helpItems", StringComparison.OrdinalIgnoreCase))321                    {322                        helpItemsNode = node;323                        break;324                    }325                }326            }327 328            if (helpItemsNode == null)329            {330                s_tracer.WriteLine("Unable to find 'helpItems' element in file {0}", helpFile);331                return;332            }333 334            bool isMaml = IsMamlHelp(helpFile, helpItemsNode);335 336            using (this.HelpSystem.Trace(helpFile))337            {338                if (helpItemsNode.HasChildNodes)339                {340                    for (int i = 0; i < helpItemsNode.ChildNodes.Count; i++)341                    {342                        XmlNode node = helpItemsNode.ChildNodes[i];343 344                        string nodeLocalName = node.LocalName;345 346                        bool isDscResource = (string.Equals(nodeLocalName, "dscResource", StringComparison.OrdinalIgnoreCase));347 348                        if (node.NodeType == XmlNodeType.Element && isDscResource)349                        {350                            MamlCommandHelpInfo helpInfo = null;351 352                            if (isMaml)353                            {354                                if (isDscResource)355                                    helpInfo = MamlCommandHelpInfo.Load(node, HelpCategory.DscResource);356                            }357 358                            if (helpInfo != null)359                            {360                                this.HelpSystem.TraceErrors(helpInfo.Errors);361                                AddCache(helpFileIdentifier, helpInfo);362                            }363                        }364                    }365                }366            }367        }368 369        #endregion370    }371}372