예제 #1
0
        private IEnumerable <PackageProvider> FilterProvidersUsingDynamicParameters(MutableEnumerable <PackageProvider> providers, IEnumerable <PackageSource> userSpecifiedRegisteredSources, bool didUserSpecifyProviders, bool didUserSpecifySources)
        {
            var excluded = new Dictionary <string, IEnumerable <string> >(StringComparer.OrdinalIgnoreCase);

            var setparameters = DynamicParameterDictionary.Values.OfType <CustomRuntimeDefinedParameter>().Where(each => each.IsSet).ReEnumerable();

            var matchedProviders = (setparameters.Any() ? providers.Where(p => setparameters.All(each => each.Options.Any(opt => opt.ProviderName == p.ProviderName))) : providers).ReEnumerable();

            foreach (var provider in matchedProviders)
            {
                // if a 'required' parameter is not filled in, the provider should not be returned.
                // we'll collect these for warnings at the end of the filter.
                var missingRequiredParameters = DynamicParameterDictionary.Values.OfType <CustomRuntimeDefinedParameter>().Where(each => !each.IsSet && each.IsRequiredForProvider(provider.ProviderName)).ReEnumerable();
                if (!missingRequiredParameters.Any())
                {
                    yield return(provider);
                }
                else
                {
                    Collection <string> missingOptions = new Collection <string>();
                    foreach (var missingRequiredParameter in missingRequiredParameters)
                    {
                        foreach (var option in missingRequiredParameter.Options)
                        {
                            // remember these so we can warn later.
                            missingOptions.Add(option.Name);
                        }
                    }
                    excluded.Add(provider.ProviderName, missingOptions);
                }
            }

            /* TODO: provide errors in the case where everything got filtered out. Or maybe warnings?
             *
             * var mismatchedProviders = (setparameters.Any() ? providers.Where(each => !matchedProviders.Contains(each)).Where(p => setparameters.Any(each => each.Options.Any(opt => opt.ProviderName == p.ProviderName))) : Enumerable.Empty<PackageProvider>()).ReEnumerable();
             *
             * if (!found) {
             *  // we didn't find anything that matched
             *  // they specified dynamic parameters that implicitly select providers
             *  // that don't fit with the providers and sources that they initially asked for.
             *
             *  if (didUserSpecifyProviders || didUserSpecifySources) {
             *
             *      if (IsInvocation) {
             *          QueueHeldMessage(() => Error(Errors.ExcludedProvidersDueToMissingRequiredParameter, excluded.Keys, userSpecifiedSources.JoinWithComma()));
             *      }
             *
             *      yield break;
             *
             *  }
             *
             *  if (didUserSpecifySources) {
             *      // user gave sources which implied some providers but the dynamic parameters implied different providers
             *      if (IsInvocation) {
             *          // error
             *      }
             *      // return empty set
             *      return result;
             *  }
             *
             *  // well, this is silly.
             *  // if the user didn't specify a source or a provider
             *  // but the FilterProvidersUsingDynamicParameters came back empty
             *  // that means that they user specified parameters from two conflicting providers
             *  // and they forced each other out!
             *
             *  if (IsInvocation) {
             *      // error
             *
             *  }
             *
             * }
             */

            if (ProviderName != null && ProviderName.Any())
            {
                foreach (var providerName in ProviderName)
                {
                    if (excluded.ContainsKey(providerName))
                    {
                        Error(Constants.Errors.SpecifiedProviderMissingRequiredOption, providerName, excluded[providerName].JoinWithComma());
                    }
                }
            }

            // these warnings only show for providers that would have otherwise be selected.
            // if not for the missing requrired parameter.
            foreach (var mp in excluded.OrderBy(each => each.Key))
            {
                string optionsValue = mp.Value.JoinWithComma();

                if (userSpecifiedRegisteredSources.Any())
                {
                    var mp1 = mp;

                    //Check if the provider with missing dynamic parameters has been registered with the source provided by a user
                    var sources = userSpecifiedRegisteredSources.Where(source => source.ProviderName != null && source.ProviderName.EqualsIgnoreCase(mp1.Key));

                    if (didUserSpecifySources && sources.Any())
                    {
                        //Error out if the provider associated with the -source matches
                        Error(Constants.Errors.SpecifiedProviderMissingRequiredOption, mp.Key, optionsValue);
                    }
                }

                Verbose(Constants.Messages.SkippedProviderMissingRequiredOption, mp.Key, optionsValue);
            }
        }
예제 #2
0
        protected IEnumerable <SoftwareIdentity> CheckMatchedDuplicates()
        {
            // if there are overmatched packages we need to know why:
            // are they found across multiple providers?
            // are they found accross multiple sources?
            // are they all from the same source?

            foreach (var list in _resultsPerName.Values.Where(each => each != null && each.Any()))
            {
                if (list.Count == 1)
                {
                    //no overmatched
                    yield return(list.FirstOrDefault());
                }
                else
                {
                    //process the overmatched case
                    SoftwareIdentity selectedPackage = null;

                    var providers = list.Select(each => each.ProviderName).Distinct().ToArray();
                    var sources   = list.Select(each => each.Source).Distinct().ToArray();

                    //case: a user specifies -Source and multiple packages are found. In this case to determine which one should be installed,
                    //      We treat the user's package source array is in a priority order, i.e. the first package source has the highest priority.
                    //      Of course, these packages should not be from a single source with the same provider.
                    //      Example: install-package -Source @('src1', 'src2')
                    //               install-package -Source @('src1', 'src2') -Provider @('p1', 'p2')
                    if (Sources.Any() && (providers.Length != 1 || sources.Length != 1))
                    {
                        // let's use the first source as our priority.As long as we find a package, we exit the 'for' loop righ away
                        foreach (var source in Sources)
                        {
                            //select all packages matched source
                            var pkgs = list.Where(package => source.EqualsIgnoreCase(package.Source) || (UserSpecifiedSourcesList.Keys.ContainsIgnoreCase(package.Source) && source.EqualsIgnoreCase(UserSpecifiedSourcesList[package.Source]))).ToArray();
                            if (pkgs.Length == 0)
                            {
                                continue;
                            }
                            if (pkgs.Length == 1)
                            {
                                //only one provider found the package
                                selectedPackage = pkgs[0];
                                break;
                            }
                            if (ProviderName == null)
                            {
                                //user does not specify '-providerName' but we found multiple packages with a source, can not determine which one
                                //will error out
                                break;
                            }
                            if (pkgs.Length > 1)
                            {
                                //case: multiple providers matched the same source.
                                //need to process provider's priority order
                                var pkg = ProviderName.Select(p => pkgs.FirstOrDefault(each => each.ProviderName.EqualsIgnoreCase(p))).FirstOrDefault();
                                if (pkg != null)
                                {
                                    selectedPackage = pkg;
                                    break;
                                }
                            }
                        }//inner foreach

                        //case: a user specifies -Provider array but no -Source and multiple packages are found. In this case to determine which one should be installed,
                        //      We treat the user's package provider array is in a priority order, i.e. the first provider in the array has the highest priority.
                        //      Of course, these packages should not be from a single source with the same provider.
                        //      Example: install-package -Provider @('p1', 'p2')
                    }
                    else if (ProviderName != null && ProviderName.Any() && (providers.Length != 1 || sources.Length != 1))
                    {
                        foreach (var providerName in ProviderName)
                        {
                            //select all packages matched with the provider name
                            var packages = list.Where(each => providerName.EqualsIgnoreCase(each.ProviderName)).ToArray();
                            if (packages.Length == 0)
                            {
                                continue;
                            }
                            if (packages.Length == 1)
                            {
                                //only one provider found the package, that's good
                                selectedPackage = packages[0];
                                break;
                            }
                            else
                            {
                                //user does not specify '-source' but we found multiple packages with one provider, we can not determine which one
                                //will error out
                                break;
                            }
                        }
                    }

                    if (selectedPackage != null)
                    {
                        yield return(selectedPackage);
                    }
                    else
                    {
                        //error out for the overmatched case
                        var suggestion = "";
                        if (providers.Length == 1)
                        {
                            // it's matching this package multiple times in the same provider.
                            if (sources.Length == 1)
                            {
                                // matching it from a single source.
                                // be more exact on matching name? or version?
                                suggestion = Resources.Messages.SuggestRequiredVersion;
                            }
                            else
                            {
                                // it's matching the same package from multiple sources
                                // tell them to use -source
                                suggestion = Resources.Messages.SuggestSingleSource;
                            }
                        }
                        else
                        {
                            // found across multiple providers
                            // must specify -provider
                            suggestion = Resources.Messages.SuggestSingleProviderName;
                        }

                        string searchKey = null;

                        foreach (var pkg in list)
                        {
                            Warning(Constants.Messages.MatchesMultiplePackages, pkg.SearchKey, pkg.ProviderName, pkg.Name, pkg.Version, GetPackageSourceNameOrLocation(pkg));
                            searchKey = pkg.SearchKey;
                        }
                        Error(Constants.Errors.DisambiguateForInstall, searchKey, GetMessageString(suggestion, suggestion));
                    }
                }
            }
        }