-
Notifications
You must be signed in to change notification settings - Fork 905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(GH-1397) Improved choco outdated #1495
(GH-1397) Improved choco outdated #1495
Conversation
Related to #994 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, but I'd like some testing on all types of repository sources. I think that this could possibly be helpful with upgrade in cases where it isn't using a particular --version
.
/// <param name="packageInfo">The package information.</param> | ||
/// <returns>The original unmodified configuration, so it can be reset after upgrade</returns> | ||
private ChocolateyConfiguration set_package_config_for_upgrade(ChocolateyConfiguration config, ChocolateyPackageInformation packageInfo) | ||
public ConcurrentDictionary<string, PackageResult> get_outdated(ChocolateyConfiguration config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
XML comments here might be helpful 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are lower with the method Here It just showed up oddly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant, it might be beneficial to add xml comments to this method. I also noticed the spacing looks funny, how many spaces over is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are 2 tabs, they look odd on github.
This is in INugetService
/// <summary>
/// Get outdated packages
/// </summary>
/// <param name="config">The configuration.</param>
ConcurrentDictionary<string, PackageResult> get_outdated(ChocolateyConfiguration config);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
INuGetService, there we go!
|
||
foreach (var packageName in packageNames) | ||
{ | ||
var latestPackage = packageManager.SourceRepository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).FirstOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it! How does it hold up against different sources though? Specifically I think this works great when it is hitting an OData feed like the community repository, but how does it work when it hits a file share or a NuGet.Server (Chocolatey.Server is a good one to test)?
If this query is 👍 , it probably makes sense to use it for installs and upgrades as well when a specific version hasn't been passed - that would relieve some pressure against the community repository. |
e2c74bd
to
cb0c781
Compare
@@ -862,11 +862,12 @@ public void remove_rollback_directory_if_exists(string packageName) | |||
|
|||
foreach (var packageName in packageNames) | |||
{ | |||
var latestPackage = packageManager.SourceRepository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).FirstOrDefault(); | |||
// LastOrDefault to get the latest package from local repository, because all packages have set IsLatestVersion to true | |||
var latestPackage = packageManager.SourceRepository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).LastOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a weird change there.
foreach (var packageName in packageNames) | ||
{ | ||
// LastOrDefault to get the latest package from local repository, because all packages have set IsLatestVersion to true | ||
var latestPackage = packageManager.SourceRepository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).LastOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, that makes sense.
|
||
if(latestPackages.Count > 1) | ||
{ | ||
latestPackage = latestPackages.Last(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is actually a way to see if you are hitting a file repo or an OData repo. I'd take a look at that as this is not quite right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you suggest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies meant to link it. Take a look at
private static IQueryable<IPackage> execute_package_search(ChocolateyConfiguration configuration, ILogger nugetLogger) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Particularly
choco/src/chocolatey/infrastructure.app/nuget/NugetList.cs
Lines 50 to 59 in cdf0938
bool isRemote; | |
var aggregateRepo = packageRepository as AggregateRepository; | |
if (aggregateRepo != null) | |
{ | |
isRemote = aggregateRepo.Repositories.All(repo => repo is IServiceBasedRepository); | |
} | |
else | |
{ | |
isRemote = packageRepository is IServiceBasedRepository; | |
} |
{ | ||
latestPackage = latestPackages.Last(); | ||
latestPackage = repository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).SingleOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is no package in a remote source nuget produces warning [NuGet] Object reference not set to an instance of an object.
Is there a way to suppress it? If not we can call .ToList().SingleOrDefault().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are acting on that list immediately, you can .ToList()
it. No need to defer results any further.
return outdatedPackages; | ||
} | ||
|
||
private bool IsRepositoryRemote(IPackageRepository repository) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming conventions - this should be repository_is_remote
{ | ||
var repository = packageManager.SourceRepository; | ||
|
||
bool isRemote = IsRepositoryRemote(repository); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This call and the repository seem like they are not a per iteration kind of call. Might be best not to recheck that each time.
} | ||
else | ||
{ | ||
latestPackage = repository.FindPackage(packageName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happened to the method you had before? It was legit, I mentioned it was weird but then said nevermind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it in 4fa560f because LastOrDefault is not supported in remote repository and in this commit updated to use isRemote.
So if we query remote repository it gets only the latest package and when we call local repository we use the same method that old outdated used without additional parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant repository.FindPackage()
for a repository of packages, which would also have multiple versions. Note the method I linked earlier shows you how to deal with this -
choco/src/chocolatey/infrastructure.app/nuget/NugetList.cs
Lines 130 to 138 in cdf0938
if (!isRemote) | |
{ | |
results = | |
results | |
.Where(PackageExtensions.IsListed) | |
.Where(p => configuration.Prerelease || p.IsReleaseVersion()) | |
.distinct_last(PackageEqualityComparer.Id, PackageComparer.Version) | |
.AsQueryable(); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you talking about supporting Prelease
and IsListed
like in this call packageManager.SourceRepository.FindPackage(packageName, version, config.Prerelease, allowUnlisted: false);
Or are you talking about repository.FindPackage(packageName);
not be able to get the latest version of package if there are multiple versions.
This is looking really good so far! |
Just got to play with this, wow, that is lightning fast. I'm not fully sure on the urls it is generating yet:
The bit about |
@ferventcoder What the about output. This shows up when calling repository that doesn't have package. IMO it should show up only with verbose switch. At the end should be some kind of summary, how many packages where actually checked in the source, number of all installed packages and number of outdated packages |
@DamianMaslanka5 add |
It's not working, which means you may have missed something there |
nvm apparently tolower(Id) is not needed |
Chocolatey.org packages (the community repo) represents only a tiny fraction of what's out there. Most folks are using ProGet, Artifactory, Nexus, Chocolatey Simple Server or some derivative that is at https://chocolatey.org/docs/how-to-host-feed. |
We can't change the output like that (the way you have) - that would be a break in format for all of the tools using Chocolatey. I prefer to do this as a non-breaking change versus waiting for a long time to move a major version. |
This is where I'm at with a format that doesn't incur a breaking change: public ConcurrentDictionary<string, PackageResult> get_outdated(ChocolateyConfiguration config)
{
var packageManager = NugetCommon.GetPackageManager(
config,
_nugetLogger,
_packageDownloader,
installSuccessAction: null,
uninstallSuccessAction: null,
addUninstallHandler: false);
var repository = packageManager.SourceRepository;
bool isRemote = repository_is_remote(repository);
var outdatedPackages = new ConcurrentDictionary<string, PackageResult>();
set_package_names_if_all_is_specified(config, () => { config.IgnoreDependencies = true; });
var packageNames = config.PackageNames.Split(new[] { ApplicationParameters.PackageNamesSeparator }, StringSplitOptions.RemoveEmptyEntries).or_empty_list_if_null().ToList();
foreach (var packageName in packageNames)
{
var installedPackage = packageManager.LocalRepository.FindPackage(packageName);
var pkgInfo = _packageInfoService.get_package_information(installedPackage);
bool isPinned = pkgInfo.IsPinned;
// if the package is pinned and we are skipping pinned,
// move on quickly
if (isPinned && config.OutdatedCommand.IgnorePinned)
{
string pinnedLogMessage = "{0} is pinned. Skipping pinned package.".format_with(packageName);
var pinnedPackageResult = outdatedPackages.GetOrAdd(packageName, new PackageResult(installedPackage, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, installedPackage.Id)));
pinnedPackageResult.Messages.Add(new ResultMessage(ResultType.Debug, pinnedLogMessage));
pinnedPackageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, pinnedLogMessage));
continue;
}
IQueryable<IPackage> results = repository.GetPackages().Where(x => x.Id == packageName);
if (config.Prerelease && repository.SupportsPrereleasePackages)
{
results = results.Where(p => p.IsAbsoluteLatestVersion);
}
else
{
results = results.Where(p => p.IsLatestVersion);
}
if (!isRemote)
{
results = results
.Where(PackageExtensions.IsListed)
.Where(p => config.Prerelease || p.IsReleaseVersion())
.distinct_last(PackageEqualityComparer.Id, PackageComparer.Version)
.AsQueryable();
}
// get only one result, should be the latest
var latestPackage = results.ToList().SingleOrDefault();
if (latestPackage == null)
{
if (config.Features.IgnoreUnfoundPackagesOnUpgradeOutdated) continue;
string unfoundLogMessage = "{0} was not found with the source(s) listed.{1} Source(s): \"{2}\"".format_with(packageName, Environment.NewLine, config.Sources);
var unfoundResult = outdatedPackages.GetOrAdd(packageName, new PackageResult(installedPackage, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, installedPackage.Id)));
unfoundResult.Messages.Add(new ResultMessage(ResultType.Warn, unfoundLogMessage));
unfoundResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, unfoundLogMessage));
this.Log().Warn("{0}|{1}|{1}|{2}".format_with(installedPackage.Id, installedPackage.Version, isPinned.to_string().to_lower()));
continue;
}
if (latestPackage.Version <= installedPackage.Version) continue;
var packageResult = outdatedPackages.GetOrAdd(packageName, new PackageResult(latestPackage, _fileSystem.combine_paths(ApplicationParameters.PackagesLocation, latestPackage.Id)));
string logMessage = "You have {0} v{1} installed. Version {2} is available based on your source(s).{3} Source(s): \"{4}\"".format_with(installedPackage.Id, installedPackage.Version, latestPackage.Version, Environment.NewLine, config.Sources);
packageResult.Messages.Add(new ResultMessage(ResultType.Note, logMessage));
this.Log().Info("{0}|{1}|{2}|{3}".format_with(installedPackage.Id, installedPackage.Version, latestPackage.Version, isPinned.to_string().to_lower()));
}
return outdatedPackages;
} |
@ferventcoder I will add
and change the output tomorrow. I tested Chocolatey Simple Server, the community repo and local folder. If you have configured sources to any of
Let me know if it works |
pulling this away from the upgrade command gave us some options, we can check for pinned and ignore and not even reach out to search. |
I updated the code above. If you can squash your commits down tomorrow and maybe look at flipping over to the above, I think we'll be set. If not, I can take care of squashing and then add an additional commit to use this format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than a few whitespace changes, and assuming we are using a combination of both pieces of work, this LGTM! 😄
using configuration; | ||
using chocolatey.infrastructure.results; | ||
using configuration; | ||
using System.Collections.Concurrent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nitpick... System namespaces should appear first, before any other namespaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I was nitpicky ;)
|
||
public interface INugetService : ISourceRunner | ||
public interface INugetService : ISourceRunner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like there is a whitespace issue here, where the main definition is bumped over an extra tab.
@@ -49,5 +51,11 @@ public interface INugetService : ISourceRunner | |||
/// </summary> | |||
/// <param name="packageName">Name of the package.</param> | |||
void remove_rollback_directory_if_exists(string packageName); | |||
|
|||
/// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this method is bumped over an extra tab as well, i.e. it isn't inline with the other methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub by default shows tabs as 8 spaces instead of 4 add ?ts=4 to file view url, it doesn't work with diffs.
Anyway I will convert tabs to spaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, thanks!
} | ||
|
||
// Call .ToList() to prevent warning from NuGet if package is not found in a remote repository | ||
var latestPackage = results.ToList().SingleOrDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This throws exceptions, if we use multiple sources, because we get 2 packages if they exists in both sources. Should we just move .distinct_last(PackageEqualityComparer.Id, PackageComparer.Version)
outside if (!isRemote)
and take package with the highest version? Or we shouldn't support multiple sources at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DamianMaslanka5 that's a good observation. Are you on Gitter? https://gitter.im/chocolatey/choco - we could discuss in more realtime.
Added get_outdated to NugetService for simplifiation. "packageManager.SourceRepository.FindPackage" downloaded data about all versions of a package instead of only the latest. Now "packageManager.SourceRepository.GetPackages()" is used to get only the latest version of a package.
ecc88e4
to
3266258
Compare
Howdy, this has been rebased onto stable, rebased on merge conflicts, then rebased to squash down the commits and merged into stable at 31fe5e3. Thanks for the contribution, this is going to be great!! |
Added get_outdated in NugetService to make it more readable.
Used
packageManager.SourceRepository.GetPackages().Where(x => x.Id.ToLower() == packageName && x.IsLatestVersion).FirstOrDefault();
to get the latest version of package instead of
packageManager.SourceRepository.FindPackage(packageName, version, config.Prerelease, allowUnlisted: false);
which downloads data about all versions of a package.
#1397