Skip to content

Commit

Permalink
(chocolateyGH-431) Add Count to IListCommand
Browse files Browse the repository at this point in the history
Updated List to use IQueryable all the way down.
Added count with efficiently takes advantage of IQueryable change to provide quick counts of results.

Added a fall-through branch for non-remote repositories that don't handle certain filters and sorts automatically.
  • Loading branch information
Richard Simpson committed Sep 28, 2015
1 parent 0350608 commit 5433f8d
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 8 deletions.
9 changes: 9 additions & 0 deletions src/chocolatey/GetChocolatey.cs
Expand Up @@ -222,6 +222,15 @@ public IEnumerable<T> List<T>()
var runner = new GenericRunner();
return runner.list<T>(configuration, _container, isConsole: false, parseArgs: null);
}

public int Count()
{
extract_resources();
var configuration = create_configuration(new List<string>());
configuration.RegularOutput = true;
var runner = new GenericRunner();
return runner.count(configuration, _container, isConsole: false, parseArgs: null);
}
}

// ReSharper restore InconsistentNaming
Expand Down
Expand Up @@ -140,6 +140,12 @@ public IEnumerable<PackageResult> list(ChocolateyConfiguration configuration)
return _packageService.list_run(configuration);
}

public int count(ChocolateyConfiguration config)
{
config.QuietOutput = true;
return _packageService.count_run(config);
}

public bool may_require_admin_access()
{
return false;
Expand Down
Expand Up @@ -148,6 +148,11 @@ public IEnumerable<ChocolateySource> list(ChocolateyConfiguration configuration)
return _configSettingsService.source_list(configuration);
}

public int count(ChocolateyConfiguration config)
{
return list(config).Count();
}

public bool may_require_admin_access()
{
return true;
Expand Down
58 changes: 51 additions & 7 deletions src/chocolatey/infrastructure.app/nuget/NugetList.cs
Expand Up @@ -17,6 +17,7 @@ namespace chocolatey.infrastructure.app.nuget
{
using System.Collections.Generic;
using System.Linq;

using NuGet;
using configuration;

Expand All @@ -25,13 +26,48 @@ namespace chocolatey.infrastructure.app.nuget
public static class NugetList
{
public static IEnumerable<IPackage> GetPackages(ChocolateyConfiguration configuration, ILogger nugetLogger)
{
return execute_package_search(configuration, nugetLogger);
}


public static int GetCount(ChocolateyConfiguration configuration, ILogger nugetLogger)
{
return execute_package_search(configuration, nugetLogger).Count();
}

private static IQueryable<IPackage> execute_package_search(ChocolateyConfiguration configuration, ILogger nugetLogger)
{
var packageRepository = NugetCommon.GetRemoteRepository(configuration, nugetLogger);

// Whether or not the package is remote determines two things:
// 1. Does the repository have a notion of "listed"?
// 2. Does it support prerelease in a straight-forward way?
// Choco previosly dealt with this by taking the path of least resistance and manually filtering out and sort unwanted packages
// This result in blocking operations that didn't let service based repositories, like OData, take care of heavy lifting on the server.
bool isRemote;
var aggregateRepo = packageRepository as AggregateRepository;
if (aggregateRepo != null)
{
isRemote = aggregateRepo.Repositories.All(repo => repo is IServiceBasedRepository);
}
else
{
isRemote = packageRepository is IServiceBasedRepository;
}

IQueryable<IPackage> results = packageRepository.Search(configuration.Input, configuration.Prerelease);

if (configuration.AllVersions)
{
return results.Where(PackageExtensions.IsListed).OrderBy(p => p.Id);
if (isRemote)
{
return results.OrderBy(p => p.Id);
}
else
{
return results.Where(PackageExtensions.IsListed).OrderBy(p => p.Id).AsQueryable();
}
}

if (configuration.Prerelease && packageRepository.SupportsPrereleasePackages)
Expand All @@ -43,17 +79,25 @@ public static IEnumerable<IPackage> GetPackages(ChocolateyConfiguration configur
results = results.Where(p => p.IsLatestVersion);
}

if (!isRemote)
{
results =
results
.Where(PackageExtensions.IsListed)
.Where(p => configuration.Prerelease || p.IsReleaseVersion())
.distinct_last(PackageEqualityComparer.Id, PackageComparer.Version)
.AsQueryable();
}

if (configuration.ListCommand.Page.HasValue)
{
results = results.Skip(configuration.ListCommand.PageSize * configuration.ListCommand.Page.Value).Take(configuration.ListCommand.PageSize);
}

return results.OrderBy(p => p.Id)
.AsEnumerable()
.Where(PackageExtensions.IsListed)
.Where(p => configuration.Prerelease || p.IsReleaseVersion())
.distinct_last(PackageEqualityComparer.Id, PackageComparer.Version);
}
return results.OrderBy(p => p.Id);
}


}

// ReSharper restore InconsistentNaming
Expand Down
18 changes: 18 additions & 0 deletions src/chocolatey/infrastructure.app/runners/GenericRunner.cs
Expand Up @@ -150,6 +150,24 @@ public IEnumerable<T> list<T>(ChocolateyConfiguration config, Container containe
}
}

public int count(ChocolateyConfiguration config, Container container, bool isConsole, Action<ICommand> parseArgs)
{
var command = find_command(config, container, isConsole, parseArgs) as IListCommand;
if (command == null)
{
if (!string.IsNullOrWhiteSpace(config.CommandName))
{
throw new Exception("The implementation of '{0}' does not support listing.".format_with(config.CommandName));
}
return 0;
}
else
{
this.Log().Debug("_ {0}:{1} - Normal Count Mode _".format_with(ApplicationParameters.Name, command.GetType().Name));
return command.count(config);
}
}

public void warn_when_admin_needs_elevation(ChocolateyConfiguration config)
{
var shouldWarn = (!config.Information.IsProcessElevated && config.Information.IsUserAdministrator);
Expand Down
Expand Up @@ -70,6 +70,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config)
perform_source_runner_action(config, r => r.ensure_source_app_installed(config, (packageResult) => handle_package_result(packageResult, config, CommandNameType.install)));
}

public int count_run(ChocolateyConfiguration config)
{
return perform_source_runner_function(config, r => r.count_run(config));
}

private void perform_source_runner_action(ChocolateyConfiguration config, Action<ISourceRunner> action)
{
var runner = _sourceRunners.FirstOrDefault(r => r.SourceType == config.SourceType);
Expand Down
5 changes: 5 additions & 0 deletions src/chocolatey/infrastructure.app/services/CygwinService.cs
Expand Up @@ -156,6 +156,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
set_root_dir_if_not_set();
}

public int count_run(ChocolateyConfiguration config)
{
throw new NotImplementedException("Count is not supported for this source runner.");
}

public void set_root_dir_if_not_set()
{
if (!string.IsNullOrWhiteSpace(_rootDirectory)) return;
Expand Down
Expand Up @@ -32,6 +32,13 @@ public interface IChocolateyPackageService
/// <param name="config">The configuration.</param>
void ensure_source_app_installed(ChocolateyConfiguration config);

/// <summary>
/// Retrieves the count of items that meet the search criteria.
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
int count_run(ChocolateyConfiguration config);

/// <summary>
/// Run list in noop mode
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/chocolatey/infrastructure.app/services/ISourceRunner.cs
Expand Up @@ -39,6 +39,13 @@ public interface ISourceRunner
/// <param name="ensureAction">The action to continue with as part of the install</param>
void ensure_source_app_installed(ChocolateyConfiguration config, Action<PackageResult> ensureAction);

/// <summary>
/// Retrieve the listed packages from the source feed cout
/// </summary>
/// <param name="config">The configuration.</param>
/// <returns>Packages count</returns>
int count_run(ChocolateyConfiguration config);

/// <summary>
/// Run list in noop mode
/// </summary>
Expand Down
21 changes: 21 additions & 0 deletions src/chocolatey/infrastructure.app/services/NugetService.cs
Expand Up @@ -75,6 +75,27 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
// nothing to do. Nuget.Core is already part of Chocolatey
}

public int count_run(ChocolateyConfiguration config)
{
int count = 0;

if (config.ListCommand.LocalOnly)
{
config.Sources = ApplicationParameters.PackagesLocation;
config.Prerelease = true;
}

int? pageValue = config.ListCommand.Page;
try
{
return NugetList.GetCount(config, _nugetLogger);
}
finally
{
config.ListCommand.Page = pageValue;
}
}

public void list_noop(ChocolateyConfiguration config)
{
this.Log().Info("{0} would have searched for '{1}' against the following source(s) :\"{2}\"".format_with(
Expand Down
5 changes: 5 additions & 0 deletions src/chocolatey/infrastructure.app/services/PythonService.cs
Expand Up @@ -193,6 +193,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
}
}

public int count_run(ChocolateyConfiguration config)
{
throw new NotImplementedException("Count is not supported for this source runner.");
}

public void set_executable_path_if_not_set()
{
if (!string.IsNullOrWhiteSpace(_exePath)) return;
Expand Down
5 changes: 5 additions & 0 deletions src/chocolatey/infrastructure.app/services/RubyGemsService.cs
Expand Up @@ -126,6 +126,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
}
}

public int count_run(ChocolateyConfiguration config)
{
throw new NotImplementedException("Count is not supported for this source runner.");
}

public void list_noop(ChocolateyConfiguration config)
{
var args = ExternalCommandArgsBuilder.build_arguments(config, _listArguments);
Expand Down
5 changes: 5 additions & 0 deletions src/chocolatey/infrastructure.app/services/WebPiService.cs
Expand Up @@ -122,6 +122,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
}
}

public int count_run(ChocolateyConfiguration config)
{
throw new NotImplementedException("Count is not supported for this source runner.");
}

public void list_noop(ChocolateyConfiguration config)
{
var args = ExternalCommandArgsBuilder.build_arguments(config, _listArguments);
Expand Down
Expand Up @@ -157,6 +157,11 @@ public void ensure_source_app_installed(ChocolateyConfiguration config, Action<P
set_executable_path_if_not_set();
}

public int count_run(ChocolateyConfiguration config)
{
throw new NotImplementedException("Count is not supported for this source runner.");
}

public void set_executable_path_if_not_set()
{
if (!string.IsNullOrWhiteSpace(_exePath)) return;
Expand Down
7 changes: 6 additions & 1 deletion src/chocolatey/infrastructure/commands/IListCommand.cs
Expand Up @@ -18,7 +18,12 @@ namespace chocolatey.infrastructure.commands
using System.Collections.Generic;
using app.configuration;

public interface IListCommand<out T> : ICommand
public interface IListCommand : ICommand
{
int count(ChocolateyConfiguration config);
}

public interface IListCommand<out T> : IListCommand
{
IEnumerable<T> list(ChocolateyConfiguration config);
}
Expand Down

0 comments on commit 5433f8d

Please sign in to comment.