Пример #1
0
        private static JsonCaseInsensitiveStringDictionary <TValue> StringDictionaryUnion <TValue>(
            JsonCaseInsensitiveStringDictionary <TValue> thisStringDict,
            JsonCaseInsensitiveStringDictionary <TValue> thatStringDict,
            Func <TValue, TValue, object> valueUnionizer = null)
            where TValue : ICloneable
        {
            if (thatStringDict == null)
            {
                return(thisStringDict);
            }

            if (thisStringDict == null)
            {
                return((JsonCaseInsensitiveStringDictionary <TValue>)thatStringDict.Clone());
            }

            foreach (KeyValuePair <string, TValue> item in thatStringDict)
            {
                if (!thisStringDict.ContainsKey(item.Key))
                {
                    thisStringDict.Add(item.Key, item.Value);
                    continue;
                }

                if (valueUnionizer != null)
                {
                    thisStringDict[item.Key] = (TValue)valueUnionizer(thisStringDict[item.Key], item.Value);
                }
            }

            return(thisStringDict);
        }
Пример #2
0
        /// <summary>
        /// Collate an AssemblyData object for a single assembly.
        /// </summary>
        /// <param name="asm">the assembly to collect data on.</param>
        /// <returns>A pair of the name and data of the given assembly.</returns>
        public static KeyValuePair <string, AssemblyData> AssembleAssembly(Assembly asm)
        {
            AssemblyName asmName = asm.GetName();

            var asmNameData = new AssemblyNameData()
            {
                Name           = asmName.Name,
                Version        = asmName.Version,
                Culture        = string.IsNullOrEmpty(asmName.CultureName) ? null : asmName.CultureName,
                PublicKeyToken = asmName.GetPublicKeyToken(),
            };

            Type[] types = asm.GetTypes();
            JsonCaseInsensitiveStringDictionary <JsonCaseInsensitiveStringDictionary <TypeData> > namespacedTypes = null;

            if (types.Any())
            {
                namespacedTypes = new JsonCaseInsensitiveStringDictionary <JsonCaseInsensitiveStringDictionary <TypeData> >();
                foreach (Type type in asm.GetTypes())
                {
                    if (!type.IsPublic)
                    {
                        continue;
                    }

                    // Some types don't have a namespace, but we still want to file them
                    string typeNamespace = type.Namespace ?? "";

                    if (!namespacedTypes.ContainsKey(typeNamespace))
                    {
                        namespacedTypes.Add(typeNamespace, new JsonCaseInsensitiveStringDictionary <TypeData>());
                    }

                    TypeData typeData = AssembleType(type);

                    namespacedTypes[typeNamespace][type.Name] = typeData;
                }
            }

            var asmData = new AssemblyData()
            {
                AssemblyName = asmNameData,
                Types        = namespacedTypes
            };

            return(new KeyValuePair <string, AssemblyData>(asmName.Name, asmData));
        }
Пример #3
0
        /// <summary>
        /// Collate type data from assemblies into an AvailableTypeData object.
        /// </summary>
        /// <param name="assemblies">the assemblies to collate data from.</param>
        /// <param name="typeAccelerators">lookup table of PowerShell type accelerators.</param>
        /// <returns>an object describing all the available types from the given assemblies.</returns>
        public static AvailableTypeData AssembleAvailableTypes(
            IEnumerable <Assembly> assemblies,
            IDictionary <string, Type> typeAccelerators,
            out IEnumerable <CompatibilityAnalysisException> errors)
        {
            var errAcc = new List <CompatibilityAnalysisException>();
            var typeAcceleratorDict = new JsonCaseInsensitiveStringDictionary <TypeAcceleratorData>(typeAccelerators.Count);

            foreach (KeyValuePair <string, Type> typeAccelerator in typeAccelerators)
            {
                var ta = new TypeAcceleratorData()
                {
                    Assembly = typeAccelerator.Value.Assembly.GetName().Name,
                    Type     = typeAccelerator.Value.FullName
                };

                typeAcceleratorDict.Add(typeAccelerator.Key, ta);
            }

            var asms = new JsonCaseInsensitiveStringDictionary <AssemblyData>();

            foreach (Assembly asm in assemblies)
            {
                // Don't want to include this module or assembly in the output
                if (Assembly.GetCallingAssembly() == asm)
                {
                    continue;
                }

                try
                {
                    KeyValuePair <string, AssemblyData> asmData = AssembleAssembly(asm);
                    asms.Add(asmData.Key, asmData.Value);
                }
                catch (ReflectionTypeLoadException e)
                {
                    errAcc.Add(new CompatibilityAnalysisException($"Failed to load assembly '{asm.GetName().FullName}'", e));
                }
            }

            errors = errAcc;
            return(new AvailableTypeData()
            {
                TypeAccelerators = typeAcceleratorDict,
                Assemblies = asms
            });
        }
Пример #4
0
        /// <summary>
        /// Assembly module data objects into a lookup table.
        /// </summary>
        /// <param name="modules">An enumeration of module data objects to assemble</param>
        /// <returns>A case-insensitive dictionary of versioned module data objects.</returns>
        public JsonCaseInsensitiveStringDictionary <JsonDictionary <Version, ModuleData> > AssembleModulesData(
            IEnumerable <Tuple <string, Version, ModuleData> > modules)
        {
            var moduleDict = new JsonCaseInsensitiveStringDictionary <JsonDictionary <Version, ModuleData> >();

            foreach (Tuple <string, Version, ModuleData> module in modules)
            {
                if (moduleDict.TryGetValue(module.Item1, out JsonDictionary <Version, ModuleData> versionDict))
                {
                    versionDict.Add(module.Item2, module.Item3);
                    continue;
                }

                var newVersionDict = new JsonDictionary <Version, ModuleData>();
                newVersionDict.Add(module.Item2, module.Item3);
                moduleDict.Add(module.Item1, newVersionDict);
            }

            return(moduleDict);
        }
        /// <summary>
        /// Collate type data from assemblies into an AvailableTypeData object.
        /// </summary>
        /// <param name="assemblies">the assemblies to collate data from.</param>
        /// <param name="typeAccelerators">lookup table of PowerShell type accelerators.</param>
        /// <returns>an object describing all the available types from the given assemblies.</returns>
        public AvailableTypeData AssembleAvailableTypes(
            IEnumerable <Assembly> assemblies,
            IReadOnlyDictionary <string, Type> typeAccelerators,
            out IEnumerable <CompatibilityAnalysisException> errors)
        {
            var errAcc = new List <CompatibilityAnalysisException>();
            var typeAcceleratorDict = new JsonCaseInsensitiveStringDictionary <TypeAcceleratorData>(typeAccelerators.Count);

            foreach (KeyValuePair <string, Type> typeAccelerator in typeAccelerators)
            {
                var ta = new TypeAcceleratorData()
                {
                    Assembly = typeAccelerator.Value.Assembly.GetName().Name,
                    Type     = typeAccelerator.Value.FullName
                };

                typeAcceleratorDict.Add(typeAccelerator.Key, ta);
            }

            var asms = new JsonDictionary <string, AssemblyData>();

            foreach (Assembly asm in assemblies)
            {
                // Skip over this
                if (asm == s_executingAssembly ||
                    asm.IsDynamic ||
                    string.IsNullOrEmpty(asm.Location))
                {
                    continue;
                }

                if (_excludedAssemblyPathPrefixes != null &&
                    IsAssemblyPathExcluded(asm.Location))
                {
                    continue;
                }

                try
                {
                    // First check whether an assembly with this name already exists
                    // Only replace it if the current one is newer
                    AssemblyName asmName = asm.GetName();
                    if (asms.TryGetValue(asmName.Name, out AssemblyData currentAssemblyData) &&
                        asmName.Version < currentAssemblyData.AssemblyName.Version)
                    {
                        continue;
                    }

                    KeyValuePair <string, AssemblyData> asmData = AssembleAssembly(asm);
                    try
                    {
                        asms.Add(asmData.Key, asmData.Value);
                    }
                    catch (ArgumentException e)
                    {
                        // We don't have a way in the schema for two assemblies with the same name, so we just keep the first
                        // This is not really valid and we should update the schema to subkey the version
                        errAcc.Add(new CompatibilityAnalysisException($"Found duplicate assemblies with name {asmData.Key}. Kept the first one.", e));
                    }
                }
                catch (Exception e) when(e is ReflectionTypeLoadException || e is FileNotFoundException)
                {
                    errAcc.Add(new CompatibilityAnalysisException($"Failed to load assembly '{asm.GetName().FullName}'", e));
                }
            }

            errors = errAcc;
            return(new AvailableTypeData()
            {
                TypeAccelerators = typeAcceleratorDict,
                Assemblies = asms
            });
        }
        /// <summary>
        /// Get a module data object for the Microsoft.PowerShell.Core pseudo-module.
        /// The version is given as the PowerShell version.
        /// </summary>
        /// <returns>The name, version and data of the core pseudo-module.</returns>
        public Tuple <string, Version, ModuleData> GetCoreModuleData()
        {
            var moduleData = new ModuleData();

            IEnumerable <CommandInfo> coreCommands = _pwsh.AddCommand(GcmInfo)
                                                     .AddParameter("Module", CORE_MODULE_NAME)
                                                     .InvokeAndClear <CommandInfo>();

            var cmdletData   = new JsonCaseInsensitiveStringDictionary <CmdletData>();
            var functionData = new JsonCaseInsensitiveStringDictionary <FunctionData>();

            foreach (CommandInfo command in coreCommands)
            {
                switch (command)
                {
                case CmdletInfo cmdlet:
                    try
                    {
                        cmdletData.Add(cmdlet.Name, GetSingleCmdletData(cmdlet));
                    }
                    catch (RuntimeException)
                    {
                        // If we can't load the cmdlet, we just move on
                    }
                    continue;

                case FunctionInfo function:
                    try
                    {
                        functionData.Add(function.Name, GetSingleFunctionData(function));
                    }
                    catch (RuntimeException)
                    {
                        // Some functions have problems loading,
                        // which likely means PowerShell wouldn't be able to run them
                    }
                    continue;

                default:
                    throw new CompatibilityAnalysisException($"Command {command.Name} in core module is of unsupported type {command.CommandType}");
                }
            }

            moduleData.Cmdlets   = cmdletData;
            moduleData.Functions = functionData;

            // Get default variables and core aliases out of a fresh runspace
            using (SMA.PowerShell freshPwsh = SMA.PowerShell.Create(RunspaceMode.NewRunspace))
            {
                Collection <PSObject> varsAndAliases = freshPwsh.AddCommand("Get-ChildItem")
                                                       .AddParameter("Path", "variable:,alias:")
                                                       .InvokeAndClear();

                var variables = new List <string>();
                var aliases   = new JsonCaseInsensitiveStringDictionary <string>();

                foreach (PSObject returnedObject in varsAndAliases)
                {
                    switch (returnedObject.BaseObject)
                    {
                    case PSVariable variable:
                        variables.Add(variable.Name);
                        continue;

                    case AliasInfo alias:
                        aliases.Add(alias.Name, GetSingleAliasData(alias));
                        continue;

                        // Skip over other objects we get back, since there's no reason to throw
                    }
                }

                moduleData.Variables = variables.ToArray();
                moduleData.Aliases   = aliases;
            }

            Version psVersion = _psVersion.PreReleaseLabel != null
                ? new Version(_psVersion.Major, _psVersion.Minor, _psVersion.Build)
                : (Version)_psVersion;

            return(new Tuple <string, Version, ModuleData>(CORE_MODULE_NAME, psVersion, moduleData));
        }
        /// <summary>
        /// Get a module data object for the Microsoft.PowerShell.Core pseudo-module.
        /// The version is given as the PowerShell version.
        /// </summary>
        /// <returns>The name, version and data of the core pseudo-module.</returns>
        public Tuple <string, Version, ModuleData> GetCoreModuleData()
        {
            var moduleData = new ModuleData();

            IEnumerable <CommandInfo> coreCommands = _pwsh.AddCommand(GcmInfo)
                                                     .AddParameter("Type", CommandTypes.Alias | CommandTypes.Cmdlet | CommandTypes.Function)
                                                     .InvokeAndClear <CommandInfo>()
                                                     .Where(commandInfo => string.IsNullOrEmpty(commandInfo.ModuleName) || CORE_MODULE_NAME.Equals(commandInfo.ModuleName, StringComparison.OrdinalIgnoreCase));

            var cmdletData       = new JsonCaseInsensitiveStringDictionary <CmdletData>();
            var functionData     = new JsonCaseInsensitiveStringDictionary <FunctionData>();
            var aliases          = new JsonCaseInsensitiveStringDictionary <string>();
            var aliasesToRequest = new List <string>();

            foreach (CommandInfo command in coreCommands)
            {
                switch (command)
                {
                case CmdletInfo cmdlet:
                    try
                    {
                        cmdletData.Add(cmdlet.Name, GetSingleCmdletData(cmdlet));
                    }
                    catch (RuntimeException)
                    {
                        // If we can't load the cmdlet, we just move on
                    }
                    continue;

                case FunctionInfo function:
                    try
                    {
                        functionData.Add(function.Name, GetSingleFunctionData(function));
                    }
                    catch (RuntimeException)
                    {
                        // Some functions have problems loading,
                        // which likely means PowerShell wouldn't be able to run them
                    }
                    continue;

                case AliasInfo alias:
                    try
                    {
                        // Some aliases won't resolve unless specified specifically
                        if (alias.Definition == null)
                        {
                            aliasesToRequest.Add(alias.Name);
                            continue;
                        }

                        aliases.Add(alias.Name, alias.Definition);
                    }
                    catch (RuntimeException)
                    {
                        // Ignore aliases that have trouble loading
                    }
                    continue;

                default:
                    throw new CompatibilityAnalysisException($"Command {command.Name} in core module is of unsupported type {command.CommandType}");
                }
            }

            moduleData.Cmdlets   = cmdletData;
            moduleData.Functions = functionData;

            if (aliasesToRequest != null && aliasesToRequest.Count > 0)
            {
                IEnumerable <AliasInfo> resolvedAliases = _pwsh.AddCommand(GcmInfo)
                                                          .AddParameter("Name", aliasesToRequest)
                                                          .InvokeAndClear <AliasInfo>();

                foreach (AliasInfo resolvedAlias in resolvedAliases)
                {
                    if (resolvedAlias?.Definition == null)
                    {
                        continue;
                    }

                    aliases[resolvedAlias.Name] = resolvedAlias.Definition;
                }
            }

            // Get default variables and core aliases out of a fresh runspace
            using (SMA.PowerShell freshPwsh = SMA.PowerShell.Create(RunspaceMode.NewRunspace))
            {
                Collection <PSObject> varsAndAliases = freshPwsh.AddCommand("Get-ChildItem")
                                                       .AddParameter("Path", "variable:")
                                                       .InvokeAndClear();

                var variables = new List <string>();

                foreach (PSObject returnedObject in varsAndAliases)
                {
                    switch (returnedObject.BaseObject)
                    {
                    case PSVariable variable:
                        variables.Add(variable.Name);
                        continue;

                        // Skip over other objects we get back, since there's no reason to throw
                    }
                }

                moduleData.Variables = variables.ToArray();
                moduleData.Aliases   = aliases;
            }

            Version psVersion = _psVersion.PreReleaseLabel != null
                ? new Version(_psVersion.Major, _psVersion.Minor, _psVersion.Build)
                : (Version)_psVersion;

            return(new Tuple <string, Version, ModuleData>(CORE_MODULE_NAME, psVersion, moduleData));
        }