public override bool ProcessRecordAsync() { // keep track of what package names the user asked for. if (!Name.IsNullOrEmpty()) { foreach (var name in Name) { _namesProcessed.GetOrAdd(name, () => false); } } var requests = (Name.IsNullOrEmpty() ? // if the user didn't specify any names SelectedProviders.Select(pv => new { query = "?", packages = pv.GetInstalledPackages("", this.ProviderSpecific(pv)).CancelWhen(_cancellationEvent.Token) }) : // if the user specified a name, SelectedProviders.SelectMany(pv => { // for a given provider, if we get an error, we want just that provider to stop. var host = this.ProviderSpecific(pv); return(Name.Select(name => new { query = name, packages = pv.GetInstalledPackages(name, host).CancelWhen(_cancellationEvent.Token) })); })).ToArray(); while (WaitForActivity(requests.Select(each => each.packages))) { // keep processing while any of the the queries is still going. foreach (var result in requests.Where(each => each.packages.HasData)) { // look only at requests that have data waiting. foreach (var package in result.packages.GetConsumingEnumerable()) { // process the results for that set. if (IsPackageInVersionRange(package)) { // it only counts if the package is in the range we're looking for. // mark down that we found something for that query _namesProcessed.AddOrSet(result.query, true); ProcessPackage(result.query, package); } } } // just work with whatever is not yet consumed requests = requests.FilterWithFinalizer(each => each.packages.IsConsumed, each => each.packages.Dispose()).ToArray(); } return(true); }
public override bool ProcessRecordAsync() { // keep track of what package names the user asked for. if (!Name.IsNullOrEmpty()) { foreach (var name in Name) { _namesProcessed.GetOrAdd(name, () => false); } } var requests = (Name.IsNullOrEmpty() ? // if the user didn't specify any names SelectedProviders.Select(pv => new { query = "?", packages = pv.GetInstalledPackages("", RequiredVersion, MinimumVersion, MaximumVersion, this.ProviderSpecific(pv)).CancelWhen(CancellationEvent.Token) }) : // if the user specified a name, SelectedProviders.SelectMany(pv => { // for a given provider, if we get an error, we want just that provider to stop. var host = this.ProviderSpecific(pv); return(Name.Select(name => new { query = name, packages = pv.GetInstalledPackages(name, RequiredVersion, MinimumVersion, MaximumVersion, host).CancelWhen(CancellationEvent.Token) })); })).ToArray(); var potentialPackagesToProcess = new System.Collections.ObjectModel.Collection <SoftwareIdentity>(); while (WaitForActivity(requests.Select(each => each.packages))) { // keep processing while any of the the queries is still going. foreach (var result in requests.Where(each => each.packages.HasData)) { // look only at requests that have data waiting. foreach (var package in result.packages.GetConsumingEnumerable()) { // process the results for that set. if (IsPackageInVersionRange(package)) { // it only counts if the package is in the range we're looking for. // mark down that we found something for that query _namesProcessed.AddOrSet(result.query, true); potentialPackagesToProcess.Add(package); } } } // just work with whatever is not yet consumed requests = requests.FilterWithFinalizer(each => each.packages.IsConsumed, each => each.packages.Dispose()).ToArray(); } // end of WaitForActivity() // post processing the potential packages as we have to display only // 1 package per name (note multiple versions of the same package may be installed) // In general, it is good practice to show only the latest one. foreach (var potentialPackage in from p in potentialPackagesToProcess group p by p.Name into grouping select grouping.OrderByDescending(pp => pp, SoftwareIdentityVersionComparer.Instance).First() ) { ProcessPackage(potentialPackage.CanonicalId, potentialPackage); } return(true); }
protected void SearchForPackages() { var providers = SelectedProviders.ToArray(); // filter the items into three types of searches _names = Name.IsNullOrEmpty() ? string.Empty.SingleItemAsEnumerable() : Name.Where(each => !IsUri(each) && !IsFile(each)).ToArray(); var requests = SelectedProviders.SelectMany(pv => { // for a given provider, if we get an error, we want just that provider to stop. var host = this.ProviderSpecific(pv); var a = _uris.Select(uri => new { query = new List <string> { uri.AbsolutePath }, provider = pv, packages = pv.FindPackageByUri(uri, host).CancelWhen(CancellationEvent.Token) }); var b = _files.Keys.Where(file => pv.IsSupportedFile(_files[file].Item2)).Select(file => new { query = _files[file].Item1, provider = pv, packages = pv.FindPackageByFile(file, host) }); var c = _names.Select(name => new { query = new List <string> { name }, provider = pv, packages = pv.FindPackage(name, RequiredVersion, MinimumVersion, MaximumVersion, host) }); return(a.Concat(b).Concat(c)); }).ToArray(); if (AllVersions || !SpecifiedMinimumOrMaximum) { // the user asked for every version or they didn't specify any version ranges // either way, that means that we can just return everything that we're finding. while (WaitForActivity(requests.Select(each => each.packages))) { // keep processing while any of the the queries is still going. foreach (var result in requests.Where(each => each.packages.HasData)) { // look only at requests that have data waiting. foreach (var package in result.packages.GetConsumingEnumerable()) { // process the results for that set. ProcessPackage(result.provider, result.query, package); } } // filter out whatever we're done with. requests = requests.FilterWithFinalizer(each => each.packages.IsConsumed, each => each.packages.Dispose()).ToArray(); } } else { // now this is where it gets a bit funny. // the user specified a min or max // and so we have to only return the highest one in the set for a given package. while (WaitForActivity(requests.Select(each => each.packages))) { // keep processing while any of the the queries is still going. foreach (var perProvider in requests.GroupBy(each => each.provider)) { foreach (var perQuery in perProvider.GroupBy(each => each.query)) { if (perQuery.All(each => each.packages.IsCompleted && !each.packages.IsConsumed)) { foreach (var pkg in from p in perQuery.SelectMany(each => each.packages.GetConsumingEnumerable()) group p by new { p.Name, p.Source } // for a given name into grouping // get the latest version only select grouping.OrderByDescending(pp => pp, SoftwareIdentityVersionComparer.Instance).First()) { ProcessPackage(perProvider.Key, perQuery.Key, pkg); } } } } // filter out whatever we're done with. requests = requests.FilterWithFinalizer(each => each.packages.IsConsumed, each => each.packages.Dispose()).ToArray(); } } // dispose of any requests that didn't get cleaned up earlier. foreach (var i in requests) { i.packages.Dispose(); } }
public override bool ProcessRecordAsync() { ValidateVersion(RequiredVersion); ValidateVersion(MinimumVersion); ValidateVersion(MaximumVersion); // If AllVersions is specified, make sure other version parameters are not supplied if (AllVersions.IsPresent) { if ((!string.IsNullOrWhiteSpace(RequiredVersion)) || (!string.IsNullOrWhiteSpace(MinimumVersion)) || (!string.IsNullOrWhiteSpace(MaximumVersion))) { Error(Constants.Errors.AllVersionsCannotBeUsedWithOtherVersionParameters); } } // Cannot have Max/Min version parameters with RequiredVersion if (RequiredVersion != null) { if ((!string.IsNullOrWhiteSpace(MaximumVersion)) || (!string.IsNullOrWhiteSpace(MinimumVersion))) { Error(Constants.Errors.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether); } } // keep track of what package names the user asked for. if (!Name.IsNullOrEmpty()) { foreach (var name in Name) { _namesProcessed.GetOrAdd(name, () => false); } } var requests = (Name.IsNullOrEmpty() ? // if the user didn't specify any names SelectedProviders.Select(pv => new { query = "?", packages = pv.GetInstalledPackages("", RequiredVersion, MinimumVersion, MaximumVersion, this.ProviderSpecific(pv)).CancelWhen(CancellationEvent.Token) }) : // if the user specified a name, SelectedProviders.SelectMany(pv => { // for a given provider, if we get an error, we want just that provider to stop. var host = this.ProviderSpecific(pv); return(Name.Select(name => new { query = name, packages = pv.GetInstalledPackages(name, RequiredVersion, MinimumVersion, MaximumVersion, host).CancelWhen(CancellationEvent.Token) })); })).ToArray(); var potentialPackagesToProcess = new System.Collections.ObjectModel.Collection <SoftwareIdentity>(); while (WaitForActivity(requests.Select(each => each.packages))) { // keep processing while any of the the queries is still going. foreach (var result in requests.Where(each => each.packages.HasData)) { // look only at requests that have data waiting. foreach (var package in result.packages.GetConsumingEnumerable()) { // process the results for that set. if (IsPackageInVersionRange(package)) { // it only counts if the package is in the range we're looking for. // mark down that we found something for that query _namesProcessed.AddOrSet(result.query, true); // If AllVersions is specified, process the package immediately if (AllVersions) { // Process the package immediately if -AllVersions are required ProcessPackage(package); } else { // Save to perform post-processing to eliminate duplicate versions and group by Name potentialPackagesToProcess.Add(package); } } } } // just work with whatever is not yet consumed requests = requests.FilterWithFinalizer(each => each.packages.IsConsumed, each => each.packages.Dispose()).ToArray(); } // end of WaitForActivity() // Peform post-processing only if -AllVersions is not specified if (!AllVersions) { // post processing the potential packages as we have to display only // 1 package per name (note multiple versions of the same package may be installed) // In general, it is good practice to show only the latest one. // However there are cases when the same package can be found by different providers. in that case, we will show // the packages from different providers even through they have the same package name. This is important because uninstall-package // inherts from get-package, so that when the first provider does not implement the uninstall-package(), such as Programs, others will // perform the uninstall. //grouping packages by package name first var enumerablePotentialPackages = from p in potentialPackagesToProcess group p by p.Name into grouping select grouping.OrderByDescending(pp => pp, SoftwareIdentityVersionComparer.Instance); //each group of packages with the same name, return the first if the packages are from the same provider foreach (var potentialPackage in enumerablePotentialPackages.Select(pp => (from p in pp group p by p.ProviderName into grouping select grouping.OrderByDescending(each => each, SoftwareIdentityVersionComparer.Instance).First())).SelectMany(pkgs => pkgs.ToArray())) { ProcessPackage(potentialPackage); } } return(true); }