diff --git a/src/GitExtensions.PluginManager/Plugin.cs b/src/GitExtensions.PluginManager/Plugin.cs index 626de2b..e9b3ba6 100644 --- a/src/GitExtensions.PluginManager/Plugin.cs +++ b/src/GitExtensions.PluginManager/Plugin.cs @@ -52,6 +52,7 @@ public override bool Execute(GitUIEventArgs gitUiCommands) Args args = new Args(); args.Path = pluginsPath; args.Dependencies = new List() { new Args.Dependency("GitExtensions.Extensibility") }; + args.Tags = "GitExtensions"; args.Monikers = FrameworkMonikers; args.SelfPackageId = PackageId; args.ProcessNamesToKillBeforeChange = new[] { Process.GetCurrentProcess().ProcessName }; diff --git a/src/GitExtensions.PluginManager/PluginSettings.cs b/src/GitExtensions.PluginManager/PluginSettings.cs index f869af0..3cc1231 100644 --- a/src/GitExtensions.PluginManager/PluginSettings.cs +++ b/src/GitExtensions.PluginManager/PluginSettings.cs @@ -20,7 +20,7 @@ internal class PluginSettings : IEnumerable /// /// Gets current value of . /// - public bool CloseInstances => source.GetValue(CloseInstancesProperty.Name, CloseInstancesProperty.DefaultValue, t => Boolean.Parse(t)); + public bool CloseInstances => source.GetValue(CloseInstancesProperty.Name, CloseInstancesProperty.DefaultValue, t => bool.Parse(t)); public PluginSettings(ISettingsSource source) { diff --git a/src/PackageManager.Cli/Args.cs b/src/PackageManager.Cli/Args.cs index a65b3fd..c1d78e7 100644 --- a/src/PackageManager.Cli/Args.cs +++ b/src/PackageManager.Cli/Args.cs @@ -105,16 +105,16 @@ public override string ToString() { StringBuilder result = new StringBuilder(); - if (!String.IsNullOrEmpty(Path)) + if (!string.IsNullOrEmpty(Path)) result.Append($"--path \"{Path}\""); - if (!String.IsNullOrEmpty(SelfPackageId)) + if (!string.IsNullOrEmpty(SelfPackageId)) result.Append($" --selfpackageid {SelfPackageId}"); if (IsSelfUpdate) result.Append(" --selfupdate"); - if (!String.IsNullOrEmpty(SelfOriginalPath)) + if (!string.IsNullOrEmpty(SelfOriginalPath)) result.Append($" --selforiginalpath \"{SelfOriginalPath}\""); return result.ToString(); diff --git a/src/PackageManager.Cli/Program.cs b/src/PackageManager.Cli/Program.cs index 2ac8a48..d3db83f 100644 --- a/src/PackageManager.Cli/Program.cs +++ b/src/PackageManager.Cli/Program.cs @@ -40,7 +40,7 @@ public async Task MainAsync(string[] args) UpdatesViewModel viewModel = CreateUpdatesViewModel(); await viewModel.Refresh.ExecuteAsync(); - PackageUpdateViewModel packageModel = viewModel.Packages.FirstOrDefault(p => p.Target.Id == Args.PackageId); + PackageUpdateViewModel packageModel = viewModel.Packages.FirstOrDefault(p => string.Equals(p.Target.Id, Args.PackageId, StringComparison.CurrentCultureIgnoreCase)); if (packageModel != null && viewModel.Update.CanExecute(packageModel)) { await viewModel.Update.ExecuteAsync(packageModel); diff --git a/src/PackageManager.NuGet/Models/NuGetPackage.cs b/src/PackageManager.NuGet/Models/NuGetPackage.cs index 68287d4..20c80c8 100644 --- a/src/PackageManager.NuGet/Models/NuGetPackage.cs +++ b/src/PackageManager.NuGet/Models/NuGetPackage.cs @@ -49,7 +49,7 @@ public async Task GetContentAsync(CancellationToken cancellatio => await contentService.DownloadAsync(repository, source, cancellationToken); public async Task> GetVersionsAsync(bool isPrereleaseIncluded, CancellationToken cancellationToken) - => await versionService.GetListAsync(Int32.MaxValue, source, repository, isPrereleaseIncluded: isPrereleaseIncluded, cancellationToken: cancellationToken); + => await versionService.GetListAsync(int.MaxValue, source, repository, isPrereleaseIncluded: isPrereleaseIncluded, cancellationToken: cancellationToken); public bool Equals(IPackage other) => Equals((IPackageIdentity)other); diff --git a/src/PackageManager.NuGet/Models/NuGetPackageIdentity.cs b/src/PackageManager.NuGet/Models/NuGetPackageIdentity.cs index 7101428..119a051 100644 --- a/src/PackageManager.NuGet/Models/NuGetPackageIdentity.cs +++ b/src/PackageManager.NuGet/Models/NuGetPackageIdentity.cs @@ -26,7 +26,7 @@ public bool Equals(IPackageIdentity other) if (other == null) return false; - return Id == other.Id && Version == other.Version; + return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase); } } } diff --git a/src/PackageManager.NuGet/Models/NuGetPackageSourceCollection.cs b/src/PackageManager.NuGet/Models/NuGetPackageSourceCollection.cs index 1142d33..317e5d5 100644 --- a/src/PackageManager.NuGet/Models/NuGetPackageSourceCollection.cs +++ b/src/PackageManager.NuGet/Models/NuGetPackageSourceCollection.cs @@ -17,7 +17,7 @@ public class NuGetPackageSourceCollection : DisposableBase, IPackageSourceCollec public event Action Changed; - public IPackageSource Primary => Sources.FirstOrDefault(s => s.Name == Provider.ActivePackageSourceName); + public IPackageSource Primary => Sources.FirstOrDefault(s => string.Equals(s.Name, Provider.ActivePackageSourceName, StringComparison.CurrentCultureIgnoreCase)); public IReadOnlyCollection All => Sources; public NuGetPackageSourceCollection(INuGetPackageSourceProvider provider) @@ -66,7 +66,7 @@ public void Remove(IPackageSource source) public void MarkAsPrimary(IPackageSource source) { - if (Provider.ActivePackageSourceName == source?.Name) + if (string.Equals(Provider.ActivePackageSourceName, source?.Name, StringComparison.CurrentCultureIgnoreCase)) return; if (source == null) diff --git a/src/PackageManager.NuGet/Services/EmptyNuGetSearchTermTransformer.cs b/src/PackageManager.NuGet/Services/EmptyNuGetSearchTermTransformer.cs new file mode 100644 index 0000000..4349e4b --- /dev/null +++ b/src/PackageManager.NuGet/Services/EmptyNuGetSearchTermTransformer.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PackageManager.Services +{ + public class EmptyNuGetSearchTermTransformer : INuGetSearchTermTransformer + { + public void Transform(NuGetSearchTerm searchTerm) + { + } + + public readonly static EmptyNuGetSearchTermTransformer Instance = new EmptyNuGetSearchTermTransformer(); + } +} diff --git a/src/PackageManager.NuGet/Services/INuGetPackageFilter.cs b/src/PackageManager.NuGet/Services/INuGetPackageFilter.cs index 49daccf..7543eba 100644 --- a/src/PackageManager.NuGet/Services/INuGetPackageFilter.cs +++ b/src/PackageManager.NuGet/Services/INuGetPackageFilter.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace PackageManager.Services { public interface INuGetPackageFilter { - NuGetPackageFilterResult IsPassed(IPackageSearchMetadata package); + Task FilterAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken); } } diff --git a/src/PackageManager.NuGet/Services/INuGetSearchTermTransformer.cs b/src/PackageManager.NuGet/Services/INuGetSearchTermTransformer.cs new file mode 100644 index 0000000..83a841b --- /dev/null +++ b/src/PackageManager.NuGet/Services/INuGetSearchTermTransformer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PackageManager.Services +{ + public interface INuGetSearchTermTransformer + { + void Transform(NuGetSearchTerm searchTerm); + } +} diff --git a/src/PackageManager.NuGet/Services/NuGetInstallService.cs b/src/PackageManager.NuGet/Services/NuGetInstallService.cs index c673ae3..65f523a 100644 --- a/src/PackageManager.NuGet/Services/NuGetInstallService.cs +++ b/src/PackageManager.NuGet/Services/NuGetInstallService.cs @@ -63,7 +63,7 @@ public bool IsInstalled(string packageId) using (Stream fileContent = new FileStream(ConfigFilePath, FileMode.Open)) { PackagesConfigReader reader = new PackagesConfigReader(fileContent); - return reader.GetPackages().Any(p => p.PackageIdentity.Id == packageId); + return reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, packageId, StringComparison.CurrentCultureIgnoreCase)); } } @@ -77,7 +77,7 @@ public bool IsInstalled(IPackageIdentity package) using (Stream fileContent = new FileStream(ConfigFilePath, FileMode.Open)) { PackagesConfigReader reader = new PackagesConfigReader(fileContent); - return reader.GetPackages().Any(p => p.PackageIdentity.Id == package.Id && p.PackageIdentity.Version.ToFullString() == package.Version); + return reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, package.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PackageIdentity.Version.ToFullString(), package.Version, StringComparison.CurrentCultureIgnoreCase)); } } @@ -118,7 +118,7 @@ public void Uninstall(string packageId) ReadPackageConfig( (p, cache) => { - if (p.PackageIdentity.Id == packageId) + if (string.Equals(p.PackageIdentity.Id, packageId, StringComparison.CurrentCultureIgnoreCase)) { version = p.PackageIdentity.Version; framework = p.TargetFramework; @@ -182,7 +182,7 @@ await ReadPackageConfig( { log.Debug($"Package '{package.PackageIdentity}' was found."); - NuGetPackageFilterResult filterResult = packageFilter.IsPassed(metadata); + NuGetPackageFilterResult filterResult = await packageFilter.FilterAsync(repository, metadata, cancellationToken); result.Add(new NuGetInstalledPackage( new NuGetPackage(metadata, repository, contentService, versionService), filterResult == NuGetPackageFilterResult.Ok @@ -209,7 +209,7 @@ public async Task FindInstalledAsync(string packageId, Cancell await ReadPackageConfig( (package, context) => { - if (package.PackageIdentity.Id == packageId) + if (string.Equals(package.PackageIdentity.Id, packageId, StringComparison.CurrentCultureIgnoreCase)) { result = new NuGetPackageIdentity(package.PackageIdentity); return Task.FromResult(true); diff --git a/src/PackageManager.NuGet/Services/NuGetPackageContentService.cs b/src/PackageManager.NuGet/Services/NuGetPackageContentService.cs index 09194b7..d15ac16 100644 --- a/src/PackageManager.NuGet/Services/NuGetPackageContentService.cs +++ b/src/PackageManager.NuGet/Services/NuGetPackageContentService.cs @@ -41,7 +41,7 @@ public async Task DownloadAsync(SourceRepository repository, IP using (var sourceCacheContext = new SourceCacheContext()) { var context = new PackageDownloadContext(sourceCacheContext, Path.GetTempPath(), true); - var result = await download.GetDownloadResourceResultAsync(package.Identity, context, String.Empty, nuGetLog, cancellationToken); + var result = await download.GetDownloadResourceResultAsync(package.Identity, context, string.Empty, nuGetLog, cancellationToken); if (result.Status == DownloadResourceResultStatus.Cancelled) throw new OperationCanceledException(); else if (result.Status == DownloadResourceResultStatus.NotFound) diff --git a/src/PackageManager.NuGet/Services/NuGetPackageVersionService.cs b/src/PackageManager.NuGet/Services/NuGetPackageVersionService.cs index 7c4f2fb..b2e8c33 100644 --- a/src/PackageManager.NuGet/Services/NuGetPackageVersionService.cs +++ b/src/PackageManager.NuGet/Services/NuGetPackageVersionService.cs @@ -45,10 +45,10 @@ public async Task> GetListAsync(int resultCount, IPackag try { List result = new List(); - if (await SearchOlderVersionsDirectly(result, resultCount, package, repository, versionFilter)) + if (await SearchOlderVersionsDirectlyAsync(result, resultCount, package, repository, versionFilter, cancellationToken)) return result; - if (await SearchOlderVersionsUsingMetadataResource(result, resultCount, package, repository, versionFilter, isPrereleaseIncluded, cancellationToken)) + if (await SearchOlderVersionsUsingMetadataResourceAsync(result, resultCount, package, repository, versionFilter, isPrereleaseIncluded, cancellationToken)) return result; return new List(); @@ -60,7 +60,7 @@ public async Task> GetListAsync(int resultCount, IPackag } } - private async Task SearchOlderVersionsDirectly(List result, int resultCount, IPackageSearchMetadata package, SourceRepository repository, Func versionFilter) + private async Task SearchOlderVersionsDirectlyAsync(List result, int resultCount, IPackageSearchMetadata package, SourceRepository repository, Func versionFilter, CancellationToken cancellationToken) { bool isSuccess = false; IEnumerable versions = null; @@ -81,7 +81,7 @@ private async Task SearchOlderVersionsDirectly(List result, int // TODO: Filter prelease on V2 feed. if (version.PackageSearchMetadata != null && versionFilter(package, version.PackageSearchMetadata)) { - IPackage item = ProcessOlderVersion(repository, version.PackageSearchMetadata); + IPackage item = await ProcessOlderVersionAsync(repository, version.PackageSearchMetadata, cancellationToken); if (item != null) { result.Add(item); @@ -96,7 +96,7 @@ private async Task SearchOlderVersionsDirectly(List result, int return isSuccess; } - private async Task SearchOlderVersionsUsingMetadataResource(List result, int resultCount, IPackageSearchMetadata package, SourceRepository repository, Func versionFilter, bool isPrereleaseIncluded, CancellationToken cancellationToken) + private async Task SearchOlderVersionsUsingMetadataResourceAsync(List result, int resultCount, IPackageSearchMetadata package, SourceRepository repository, Func versionFilter, bool isPrereleaseIncluded, CancellationToken cancellationToken) { PackageMetadataResource metadataResource = await repository.GetResourceAsync(cancellationToken); if (metadataResource == null) @@ -118,7 +118,7 @@ private async Task SearchOlderVersionsUsingMetadataResource(List { if (versionFilter(package, version)) { - IPackage item = ProcessOlderVersion(repository, version); + IPackage item = await ProcessOlderVersionAsync(repository, version, cancellationToken); if (item != null) { result.Add(item); @@ -132,11 +132,11 @@ private async Task SearchOlderVersionsUsingMetadataResource(List return true; } - private IPackage ProcessOlderVersion(SourceRepository repository, IPackageSearchMetadata version) + private async Task ProcessOlderVersionAsync(SourceRepository repository, IPackageSearchMetadata version, CancellationToken cancellationToken) { log.Debug($"Found '{version.Identity}'."); - NuGetPackageFilterResult filterResult = filter.IsPassed(version); + NuGetPackageFilterResult filterResult = await filter.FilterAsync(repository, version, cancellationToken); switch (filterResult) { case NuGetPackageFilterResult.Ok: diff --git a/src/PackageManager.NuGet/Services/NuGetSearchService.cs b/src/PackageManager.NuGet/Services/NuGetSearchService.cs index 11c5ca3..40eccc1 100644 --- a/src/PackageManager.NuGet/Services/NuGetSearchService.cs +++ b/src/PackageManager.NuGet/Services/NuGetSearchService.cs @@ -8,8 +8,8 @@ using Neptuo.Activators; using Neptuo.Logging; using NuGet.Common; +using NuGet.Protocol; using NuGet.Protocol.Core.Types; -using NuGet.Versioning; using PackageManager.Logging; using PackageManager.Models; @@ -25,9 +25,9 @@ public partial class NuGetSearchService : ISearchService private readonly ILogger nuGetLog; private readonly NuGetPackageVersionService versionService; private readonly INuGetPackageFilter filter; - private readonly NuGetPackageContent.IFrameworkFilter frameworkFilter; + private readonly INuGetSearchTermTransformer queryTransformer; - public NuGetSearchService(IFactory repositoryFactory, ILog log, NuGetPackageContentService contentService, NuGetPackageVersionService versionService, INuGetPackageFilter filter = null, NuGetPackageContent.IFrameworkFilter frameworkFilter = null) + public NuGetSearchService(IFactory repositoryFactory, ILog log, NuGetPackageContentService contentService, NuGetPackageVersionService versionService, INuGetPackageFilter filter = null, INuGetSearchTermTransformer termTransformer = null) { Ensure.NotNull(repositoryFactory, "repositoryFactory"); Ensure.NotNull(log, "log"); @@ -42,8 +42,8 @@ public NuGetSearchService(IFactory repositoryF this.contentService = contentService; this.nuGetLog = new NuGetLogger(log); this.versionService = versionService; - this.filter = filter; - this.frameworkFilter = frameworkFilter; + this.filter = filter ?? OkNuGetPackageFilter.Instance; + this.queryTransformer = termTransformer ?? EmptyNuGetSearchTermTransformer.Instance; } private SearchOptions EnsureOptions(SearchOptions options) @@ -60,12 +60,11 @@ private SearchOptions EnsureOptions(SearchOptions options) return options; } - private Task> SearchAsync(PackageSearchResource search, string searchText, SearchOptions options, CancellationToken cancellationToken) - => search.SearchAsync(searchText, new SearchFilter(options.IsPrereleaseIncluded), options.PageIndex * options.PageSize, options.PageSize, nuGetLog, cancellationToken); - public async Task> SearchAsync(IEnumerable packageSources, string searchText, SearchOptions options = default, CancellationToken cancellationToken = default) { - log.Debug($"Searching '{searchText}'."); + var (feedTerm, localTerm) = PrepareSearchTerms(searchText); + + log.Debug($"Searching - user text:'{searchText}'; feed query:'{feedTerm}'."); options = EnsureOptions(options); @@ -78,7 +77,6 @@ public async Task> SearchAsync(IEnumerable { log.Debug($"Loading page '{options.PageIndex}'."); - bool hasItems = false; foreach (IPackageSource packageSource in sources) { log.Debug($"Searching in '{packageSource.Uri}'."); @@ -88,30 +86,15 @@ public async Task> SearchAsync(IEnumerable if (search == null) { log.Debug($"Source skipped, because it doesn't provide '{nameof(PackageSearchResource)}'."); - continue; - } - int sourceSearchPackageCount = 0; - foreach (IPackageSearchMetadata package in await SearchAsync(search, searchText, options, cancellationToken)) - { - log.Debug($"Found '{package.Identity}'."); - - hasItems = true; - if (result.Count >= options.PageSize) - break; - - await AddPackage(result, repository, package, options.IsPrereleaseIncluded, cancellationToken); - sourceSearchPackageCount++; + sourcesToSkip.Add(packageSource); + continue; } - // If package source reached end, skip it from next probing. - if (sourceSearchPackageCount < options.PageSize) + if (!await ApplyLocalResourceSearchAsync(result, repository, search, feedTerm, localTerm, options, cancellationToken)) sourcesToSkip.Add(packageSource); } - if (!hasItems) - break; - options = new SearchOptions() { PageIndex = options.PageIndex + 1, @@ -120,15 +103,102 @@ public async Task> SearchAsync(IEnumerable foreach (IPackageSource source in sourcesToSkip) sources.Remove(source); + + if (sources.Count == 0) + break; } log.Debug($"Search completed. Found '{result.Count}' items."); return result; } - private async Task AddPackage(List result, SourceRepository repository, IPackageSearchMetadata package, bool isPrereleaseIncluded, CancellationToken cancellationToken) + /// + /// Prepares instance of terms for filtering in feed and in-app. + /// + /// + /// localTerm should always have all search terms. + /// + private (NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm) PrepareSearchTerms(string searchText) + { + NuGetSearchTerm feedTerm = new NuGetSearchTerm(); + feedTerm.Id.Add(searchText); + + queryTransformer.Transform(feedTerm); + feedTerm.Id.Remove(searchText); + + NuGetSearchTerm localTerm = null; + if (feedTerm.IsEmpty()) + { + feedTerm.Id.Add(searchText); + } + else + { + localTerm = feedTerm.Clone(); + localTerm.Id.Add(searchText); + } + + return (feedTerm, localTerm); + } + + /// + /// Tries to apply special conditions for looking in local folder feed. + /// + /// true if search reached the end of the feed; false otherwise. + private Task ApplyLocalResourceSearchAsync(List result, SourceRepository repository, PackageSearchResource search, NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm, SearchOptions options, CancellationToken cancellationToken) + { + if (search is LocalPackageSearchResource) + { + // Searching a feed from folder. Look for all packages and then filter in-app. + if (localTerm == null) + localTerm = feedTerm; + + feedTerm = new NuGetSearchTerm(); + } + + return ApplySearchAsync(result, repository, search, feedTerm, localTerm, options, cancellationToken); + } + + /// + /// Execute search on . + /// + /// true if search reached the end of the feed; false otherwise. + private async Task ApplySearchAsync(List result, SourceRepository repository, PackageSearchResource search, NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm, SearchOptions options, CancellationToken cancellationToken) + { + if (localTerm != null && options.PageSize == 1) + options.PageSize = 10; + + int sourceSearchPackageCount = 0; + foreach (IPackageSearchMetadata package in await SearchAsync(search, feedTerm.ToString(), options, cancellationToken)) + { + sourceSearchPackageCount++; + + log.Debug($"Found '{package.Identity}'."); + + if (result.Count >= options.PageSize) + break; + + if (localTerm != null && !localTerm.IsMatched(package)) + { + log.Debug($"Package skipped by late search term '{localTerm}'."); + continue; + } + + await AddPackageAsync(result, repository, package, options.IsPrereleaseIncluded, cancellationToken); + } + + // If package source reached end, skip it from next probing. + if (sourceSearchPackageCount < options.PageSize) + return false; + + return true; + } + + private Task> SearchAsync(PackageSearchResource search, string searchText, SearchOptions options, CancellationToken cancellationToken) + => search.SearchAsync(searchText, new SearchFilter(options.IsPrereleaseIncluded), options.PageIndex * options.PageSize, options.PageSize, nuGetLog, cancellationToken); + + private async Task AddPackageAsync(List result, SourceRepository repository, IPackageSearchMetadata package, bool isPrereleaseIncluded, CancellationToken cancellationToken) { - NuGetPackageFilterResult filterResult = filter.IsPassed(package); + NuGetPackageFilterResult filterResult = await filter.FilterAsync(repository, package, cancellationToken); switch (filterResult) { case NuGetPackageFilterResult.Ok: @@ -164,7 +234,7 @@ public async Task FindLatestVersionAsync(IEnumerable p IEnumerable packages = await SearchAsync(packageSources, package.Id, new SearchOptions() { PageSize = 1, IsPrereleaseIncluded = isPrereleaseIncluded }, cancellationToken); IPackage latest = packages.FirstOrDefault(); - if (latest != null && latest.Id == package.Id) + if (latest != null && string.Equals(latest.Id, package.Id, StringComparison.InvariantCultureIgnoreCase)) { log.Debug($"Found version '{latest.Version}'."); return latest; diff --git a/src/PackageManager.NuGet/Services/NuGetSearchTerm.cs b/src/PackageManager.NuGet/Services/NuGetSearchTerm.cs new file mode 100644 index 0000000..b044fbe --- /dev/null +++ b/src/PackageManager.NuGet/Services/NuGetSearchTerm.cs @@ -0,0 +1,100 @@ +using Neptuo; +using NuGet.Protocol.Core.Types; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PackageManager.Services +{ + public class NuGetSearchTerm : ICloneable + { + public List Id { get; } = new List(); + public List Version { get; } = new List(); + public List Title { get; } = new List(); + public List Tags { get; } = new List(); + public List Description { get; } = new List(); + public List Summary { get; } = new List(); + public List Owner { get; } = new List(); + + public override string ToString() + { + StringBuilder result = new StringBuilder(); + Append(result, "id", Id); + Append(result, "version", Version); + Append(result, "title", Title); + Append(result, "tags", Tags); + Append(result, "description", Description); + Append(result, "summary", Summary); + Append(result, "owner", Owner); + return result.ToString(); + } + + private void Append(StringBuilder result, string key, List values) + { + foreach (var value in values) + result.Append(" ").Append(key).Append(":").Append(value); + } + + public bool IsEmpty() + => IsEmpty(Id) + && IsEmpty(Version) + && IsEmpty(Title) + && IsEmpty(Tags) + && IsEmpty(Description) + && IsEmpty(Summary) + && IsEmpty(Owner); + + private bool IsEmpty(List values) + { + if (values.Count == 0) + return false; + + if (values.Any(s => !string.IsNullOrEmpty(s))) + return true; + + return false; + } + + public bool IsMatched(IPackageSearchMetadata package) + => IsMatched(package.Identity.Id, Id) + && IsMatched(package.Identity.Version.OriginalVersion, Version) + && IsMatched(package.Title, Title) + && IsMatched(package.Tags, Tags) + && IsMatched(package.Description, Description) + && IsMatched(package.Summary, Summary) + && IsMatched(package.Owners, Owner); + + private bool IsMatched(string packageValue, List values) + { + bool result = true; + foreach (var value in values) + { + if (string.IsNullOrEmpty(value)) + continue; + + if (packageValue.IndexOf(value, StringComparison.CurrentCultureIgnoreCase) != -1) + return true; + + result = false; + } + + return result; + } + + public NuGetSearchTerm Clone() + { + var clone = new NuGetSearchTerm(); + clone.Id.AddRange(Id); + clone.Version.AddRange(Version); + clone.Title.AddRange(Title); + clone.Tags.AddRange(Tags); + clone.Description.AddRange(Description); + clone.Summary.AddRange(Summary); + clone.Owner.AddRange(Owner); + return clone; + } + } +} diff --git a/src/PackageManager.NuGet/Services/OkNuGetPackageFilter.cs b/src/PackageManager.NuGet/Services/OkNuGetPackageFilter.cs index 2c6cae1..729b7d1 100644 --- a/src/PackageManager.NuGet/Services/OkNuGetPackageFilter.cs +++ b/src/PackageManager.NuGet/Services/OkNuGetPackageFilter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using NuGet.Protocol.Core.Types; @@ -9,31 +10,9 @@ namespace PackageManager.Services { public class OkNuGetPackageFilter : INuGetPackageFilter { - public NuGetPackageFilterResult IsPassed(IPackageSearchMetadata package) - => NuGetPackageFilterResult.Ok; + public Task FilterAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken) + => Task.FromResult(NuGetPackageFilterResult.Ok); - #region Singleton - - private static OkNuGetPackageFilter instance; - private static object instanceLock = new object(); - - public static OkNuGetPackageFilter Instance - { - get - { - if (instance == null) - { - lock (instanceLock) - { - if (instance == null) - instance = new OkNuGetPackageFilter(); - } - } - - return instance; - } - } - - #endregion + public readonly static OkNuGetPackageFilter Instance = new OkNuGetPackageFilter(); } } diff --git a/src/PackageManager.UI/App.xaml.cs b/src/PackageManager.UI/App.xaml.cs index fda0af2..99ae45c 100644 --- a/src/PackageManager.UI/App.xaml.cs +++ b/src/PackageManager.UI/App.xaml.cs @@ -45,7 +45,7 @@ protected override void OnStartup(StartupEventArgs e) .AddSerializer(MemoryLogSerializer); ILog log = LogFactory.Scope("Startup"); - log.Debug($"Startup arguments: {Environment.NewLine}{String.Join(" ", e.Args)}"); + log.Debug($"Startup arguments: {Environment.NewLine}{string.Join(" ", e.Args)}"); log.Debug($"Current version: {VersionInfo.Version}"); Args = new Args(e.Args); @@ -69,19 +69,23 @@ protected override void OnStartup(StartupEventArgs e) NuGetSourceRepositoryFactory repositoryFactory = new NuGetSourceRepositoryFactory(); INuGetPackageFilter packageFilter = null; if (Args.Dependencies.Any()) - packageFilter = new DependencyNuGetPackageFilter(Args.Dependencies, frameworks); + packageFilter = new DependencyNuGetPackageFilter(LogFactory.Scope("Filter"), Args.Dependencies, frameworks); NuGetPackageContent.IFrameworkFilter frameworkFilter = null; if (Args.Monikers.Any()) frameworkFilter = new NuGetFrameworkFilter(frameworks); + INuGetSearchTermTransformer termTransformer = null; + if (Args.Tags != null) + termTransformer = new TagsNuGetSearchTermTransformer(Args.Tags); + var selfPackageConfiguration = new SelfPackageConfiguration(Args.SelfPackageId); SelfPackageConverter.Configuration = selfPackageConfiguration; var contentService = new NuGetPackageContentService(log, frameworkFilter); var versionService = new NuGetPackageVersionService(contentService, log, packageFilter, frameworkFilter); - var searchService = new NuGetSearchService(repositoryFactory, LogFactory.Scope("Search"), contentService, versionService, packageFilter, frameworkFilter); + var searchService = new NuGetSearchService(repositoryFactory, LogFactory.Scope("Search"), contentService, versionService, packageFilter, termTransformer); var installService = new NuGetInstallService(repositoryFactory, LogFactory.Scope("Install"), Args.Path, contentService, versionService, packageFilter, frameworkFilter); var selfUpdateService = new SelfUpdateService(this, ProcessService); @@ -170,10 +174,10 @@ private void RunSelfUpdate(MainWindow wnd) updates.Refresh.Completed += async () => { bool canUpdate = false; - PackageUpdateViewModel package = updates.Packages.FirstOrDefault(p => p.Current.Id == Args.SelfPackageId); + PackageUpdateViewModel package = updates.Packages.FirstOrDefault(p => string.Equals(p.Current.Id, Args.SelfPackageId, StringComparison.CurrentCultureIgnoreCase)); if (package != null) { - if (package.Target.Version == Args.SelfUpdateVersion) + if (string.Equals(package.Target.Version, Args.SelfUpdateVersion, StringComparison.CurrentCultureIgnoreCase)) { canUpdate = true; } @@ -182,7 +186,7 @@ private void RunSelfUpdate(MainWindow wnd) if (package.Current.LoadVersions.CanExecute()) package.Current.LoadVersions.Execute(); - PackageViewModel version = package.Current.Versions.FirstOrDefault(p => p.Version == Args.SelfUpdateVersion); + PackageViewModel version = package.Current.Versions.FirstOrDefault(p => string.Equals(p.Version, Args.SelfUpdateVersion, StringComparison.CurrentCultureIgnoreCase)); if (version != null) { package.Target = version.Model; diff --git a/src/PackageManager.UI/Args.cs b/src/PackageManager.UI/Args.cs index 03c9159..42e6e1e 100644 --- a/src/PackageManager.UI/Args.cs +++ b/src/PackageManager.UI/Args.cs @@ -17,6 +17,7 @@ public partial class Args : ICloneable public bool IsSelfUpdate { get; set; } public string SelfOriginalPath { get; set; } public string SelfUpdateVersion { get; set; } + public string Tags { get; set; } public IReadOnlyCollection ProcessNamesToKillBeforeChange { get; set; } @@ -74,6 +75,9 @@ private bool ParseParameter(string name, string value) case "--dependencies": Dependencies = ParseDependencies(value); return true; + case "--tags": + Tags = value; + return true; case "--selfpackageid": SelfPackageId = value; return true; @@ -116,35 +120,38 @@ public override string ToString() { StringBuilder result = new StringBuilder(); - if (!String.IsNullOrEmpty(Path)) + if (!string.IsNullOrEmpty(Path)) result.Append($"--path \"{Path}\""); if (Monikers.Count > 0) { result.Append($" --monikers "); - result.Append(String.Join(",", Monikers)); + result.Append(string.Join(",", Monikers)); } if (Dependencies.Count > 0) { result.Append(" --dependencies "); - result.Append(String.Join(",", Dependencies.Select(d => d.Id + (d.Version != null ? "-v" + d.Version : "")))); + result.Append(string.Join(",", Dependencies.Select(d => d.Id + (d.Version != null ? "-v" + d.Version : "")))); } - if (!String.IsNullOrEmpty(SelfPackageId)) + if (!string.IsNullOrEmpty(Tags)) + result.Append($" --tags {Tags}"); + + if (!string.IsNullOrEmpty(SelfPackageId)) result.Append($" --selfpackageid {SelfPackageId}"); if (IsSelfUpdate) result.Append(" --selfupdate"); - if (!String.IsNullOrEmpty(SelfOriginalPath)) + if (!string.IsNullOrEmpty(SelfOriginalPath)) result.Append($" --selforiginalpath \"{SelfOriginalPath}\""); - if (!String.IsNullOrEmpty(SelfUpdateVersion)) + if (!string.IsNullOrEmpty(SelfUpdateVersion)) result.Append($" --selfupdateversion \"{SelfUpdateVersion}\""); if (ProcessNamesToKillBeforeChange != null && ProcessNamesToKillBeforeChange.Count > 0) - result.Append($" --processnamestokillbeforechange \"{String.Join(",", ProcessNamesToKillBeforeChange)}\""); + result.Append($" --processnamestokillbeforechange \"{string.Join(",", ProcessNamesToKillBeforeChange)}\""); return result.ToString(); } diff --git a/src/PackageManager.UI/Models/SelfPackage.cs b/src/PackageManager.UI/Models/SelfPackage.cs index 91203f4..1bf1171 100644 --- a/src/PackageManager.UI/Models/SelfPackage.cs +++ b/src/PackageManager.UI/Models/SelfPackage.cs @@ -29,7 +29,7 @@ public bool Equals(IPackageIdentity other) if (other == null) return false; - return Id == other.Id && Version == other.Version; + return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase); } } } diff --git a/src/PackageManager.UI/Services/DependencyNuGetPackageFilter.cs b/src/PackageManager.UI/Services/DependencyNuGetPackageFilter.cs index 4760eb1..357363f 100644 --- a/src/PackageManager.UI/Services/DependencyNuGetPackageFilter.cs +++ b/src/PackageManager.UI/Services/DependencyNuGetPackageFilter.cs @@ -2,54 +2,75 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Neptuo; +using Neptuo.Logging; +using NuGet.Common; using NuGet.Frameworks; using NuGet.Packaging.Core; using NuGet.Protocol.Core.Types; using NuGet.Versioning; +using PackageManager.Logging; namespace PackageManager.Services { public class DependencyNuGetPackageFilter : INuGetPackageFilter { + private readonly ILog log; + private readonly NuGetLogger nuGetLogger; private readonly IReadOnlyCollection dependencies; private readonly IReadOnlyCollection frameworks; - public DependencyNuGetPackageFilter(IReadOnlyCollection dependencies, IReadOnlyCollection frameworks) + public DependencyNuGetPackageFilter(ILog log, IReadOnlyCollection dependencies, IReadOnlyCollection frameworks) { + Ensure.NotNull(log, "log"); Ensure.NotNull(dependencies, "dependencies"); Ensure.NotNull(frameworks, "frameworks"); + this.log = log; this.dependencies = dependencies; this.frameworks = frameworks; + + nuGetLogger = new NuGetLogger(log); } - public NuGetPackageFilterResult IsPassed(IPackageSearchMetadata package) + public async Task FilterAsync(SourceRepository repository, IPackageSearchMetadata package, CancellationToken cancellationToken) { if (!dependencies.Any()) return NuGetPackageFilterResult.Ok; - foreach (var group in package.DependencySets) + DependencyInfoResource resource = await repository.GetResourceAsync(); + if (resource == null) + return NuGetPackageFilterResult.NotCompatible; + + NuGetPackageFilterResult result = NuGetPackageFilterResult.Ok; + foreach (NuGetFramework framework in frameworks) { - if (frameworks.Contains(group.TargetFramework)) + SourcePackageDependencyInfo dependencyInfo = await resource.ResolvePackage(package.Identity, framework, new SourceCacheContext(), nuGetLogger, cancellationToken); + if (dependencyInfo != null) { - NuGetPackageFilterResult result = NuGetPackageFilterResult.Ok; - // Dependency filtering: // - When incompatible dependency version is found there is a chance that previous version has the right one. // - When all dependencies are missing, don't even try previous versions. foreach (var dependency in dependencies) { - PackageDependency packageDependency = group.Packages.FirstOrDefault(p => p.Id == dependency.Id); + PackageDependency packageDependency = dependencyInfo.Dependencies.FirstOrDefault(p => string.Equals(p.Id, dependency.Id, StringComparison.CurrentCultureIgnoreCase)); if (packageDependency == null) + { + log.Info($"Package '{package.Identity}' skipped: missing dependency '{dependency.Id}'."); result = NuGetPackageFilterResult.NotCompatible; + } if (dependency.Version != null && !packageDependency.VersionRange.Satisfies(new NuGetVersion(dependency.Version))) + { + log.Info($"Package '{package.Identity}' skipped: not compatible version '{dependency.Version}' on dependency '{dependency.Id}'."); return NuGetPackageFilterResult.NotCompatibleVersion; + } } return result; } + } return NuGetPackageFilterResult.NotCompatible; diff --git a/src/PackageManager.UI/Services/TagsNuGetSearchTermTransformer.cs b/src/PackageManager.UI/Services/TagsNuGetSearchTermTransformer.cs new file mode 100644 index 0000000..6a887bc --- /dev/null +++ b/src/PackageManager.UI/Services/TagsNuGetSearchTermTransformer.cs @@ -0,0 +1,27 @@ +using Neptuo; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PackageManager.Services +{ + public class TagsNuGetSearchTermTransformer : INuGetSearchTermTransformer + { + private readonly string tags; + + public TagsNuGetSearchTermTransformer(string tags) + { + Ensure.NotNull(tags, "tags"); + this.tags = tags; + } + + public void Transform(NuGetSearchTerm searchTerm) + { + if (!string.IsNullOrEmpty(tags)) + searchTerm.Tags.Add(tags); + } + } +} diff --git a/src/PackageManager.UI/Views/Converters/DropNewLineConverter.cs b/src/PackageManager.UI/Views/Converters/DropNewLineConverter.cs index f6c3663..1069cd0 100644 --- a/src/PackageManager.UI/Views/Converters/DropNewLineConverter.cs +++ b/src/PackageManager.UI/Views/Converters/DropNewLineConverter.cs @@ -13,11 +13,11 @@ public class DropNewLineConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string target = value?.ToString(); - if (String.IsNullOrEmpty(target)) + if (string.IsNullOrEmpty(target)) return target; - target = target.Replace(Environment.NewLine, String.Empty); - target = target.Replace("\n", String.Empty); + target = target.Replace(Environment.NewLine, string.Empty); + target = target.Replace("\n", string.Empty); return target; } diff --git a/src/PackageManager.UI/Views/Converters/NullConverter.cs b/src/PackageManager.UI/Views/Converters/NullConverter.cs index a1e7bcd..cf8ebaf 100644 --- a/src/PackageManager.UI/Views/Converters/NullConverter.cs +++ b/src/PackageManager.UI/Views/Converters/NullConverter.cs @@ -21,7 +21,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn if (value is string) { string stringValue = value as string; - if (stringValue == String.Empty) + if (stringValue == string.Empty) return TrueValue; } diff --git a/src/PackageManager.UI/Views/DesignData/MockInstallService.cs b/src/PackageManager.UI/Views/DesignData/MockInstallService.cs index 4de6b5d..39beba1 100644 --- a/src/PackageManager.UI/Views/DesignData/MockInstallService.cs +++ b/src/PackageManager.UI/Views/DesignData/MockInstallService.cs @@ -18,7 +18,7 @@ public bool IsInstalled(string packageId) => false; public bool IsInstalled(IPackageIdentity package) - => Installed?.Id == package?.Id && Installed?.Version == package?.Version; + => string.Equals(Installed?.Id, package?.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Installed?.Version, package?.Version, StringComparison.CurrentCultureIgnoreCase); public void Install(IPackageIdentity package) { } diff --git a/src/PackageManager.UI/Views/DesignData/MockPackage.cs b/src/PackageManager.UI/Views/DesignData/MockPackage.cs index 67694b2..3346d1d 100644 --- a/src/PackageManager.UI/Views/DesignData/MockPackage.cs +++ b/src/PackageManager.UI/Views/DesignData/MockPackage.cs @@ -27,7 +27,7 @@ public bool Equals(IPackageIdentity other) if (other == null) return false; - return Id == other.Id && Version == other.Version; + return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase); } public bool Equals(IPackage other) diff --git a/src/PackageManager.UI/Views/LogWindow.xaml.cs b/src/PackageManager.UI/Views/LogWindow.xaml.cs index c95a762..2ca1451 100644 --- a/src/PackageManager.UI/Views/LogWindow.xaml.cs +++ b/src/PackageManager.UI/Views/LogWindow.xaml.cs @@ -32,7 +32,7 @@ public LogWindow(MemoryLogSerializer log) private async void RefreshContent() { TextContent.Text = log.GetContent(); - if (String.IsNullOrEmpty(TextContent.Text)) + if (string.IsNullOrEmpty(TextContent.Text)) TextContent.Text = "No entries."; await Task.Delay(50); diff --git a/src/PackageManager/ViewModels/Commands/SaveSourceCommand.cs b/src/PackageManager/ViewModels/Commands/SaveSourceCommand.cs index 5261168..57ef376 100644 --- a/src/PackageManager/ViewModels/Commands/SaveSourceCommand.cs +++ b/src/PackageManager/ViewModels/Commands/SaveSourceCommand.cs @@ -64,7 +64,7 @@ public override bool CanExecute() if (string.IsNullOrEmpty(Name)) return false; - if (sources.Any(s => s.Name == Name && !(edit == null || edit == s))) + if (sources.Any(s => string.Equals(s.Name, Name, StringComparison.CurrentCultureIgnoreCase) && !(edit == null || edit == s))) return false; if (string.IsNullOrEmpty(Url)) diff --git a/src/PackageManager/ViewModels/PackageSourceSelectorViewModel.cs b/src/PackageManager/ViewModels/PackageSourceSelectorViewModel.cs index 237d4f3..af6418f 100644 --- a/src/PackageManager/ViewModels/PackageSourceSelectorViewModel.cs +++ b/src/PackageManager/ViewModels/PackageSourceSelectorViewModel.cs @@ -23,10 +23,10 @@ IEnumerable IPackageSourceSelector.Sources { if (selectedSources == null) { - if (string.IsNullOrEmpty(SelectedName) || SelectedName == AllFeedName) + if (string.IsNullOrEmpty(SelectedName) || string.Equals(SelectedName, AllFeedName, StringComparison.CurrentCultureIgnoreCase)) selectedSources = service.All; else - selectedSources = new List(1) { service.All.First(s => s.Name == SelectedName) }; + selectedSources = new List(1) { service.All.First(s => string.Equals(s.Name, SelectedName, StringComparison.CurrentCultureIgnoreCase)) }; } return selectedSources; @@ -48,10 +48,13 @@ public string SelectedName selectedSources = null; - if (value == null) - service.MarkAsPrimary(null); - else - service.MarkAsPrimary(service.All.FirstOrDefault(s => s.Name == value)); + if (!isServiceUpdating) + { + if (value == null) + service.MarkAsPrimary(null); + else + service.MarkAsPrimary(service.All.FirstOrDefault(s => string.Equals(s.Name, value, StringComparison.CurrentCultureIgnoreCase))); + } } } } @@ -68,32 +71,43 @@ public PackageSourceSelectorViewModel(IPackageSourceCollection service) private void OnServiceChanged() { - string selectedName = SelectedName; - SourceNames.Clear(); - - bool isSelectedNameContained = false; - void Add(string name) + try { - if (!isSelectedNameContained) - isSelectedNameContained = name == selectedName; + isServiceUpdating = true; - SourceNames.Add(name); - } + string selectedName = SelectedName; + SourceNames.Clear(); - if (service.All.Count > 1) - Add(AllFeedName); + bool isSelectedNameContained = false; + void Add(string name) + { + if (!isSelectedNameContained) + isSelectedNameContained = name == selectedName; + + SourceNames.Add(name); + } - foreach (IPackageSource source in service.All) - Add(source.Name); + if (service.All.Count > 1) + Add(AllFeedName); - if (isSelectedNameContained) - SelectedName = selectedName; - else if(service.Primary != null) - SelectedName = SourceNames.FirstOrDefault(s => s == service.Primary.Name); - else - SelectedName = SourceNames.FirstOrDefault(); + foreach (IPackageSource source in service.All) + Add(source.Name); + + if (isSelectedNameContained) + SelectedName = selectedName; + else if (service.Primary != null) + SelectedName = SourceNames.FirstOrDefault(s => string.Equals(s, service.Primary.Name, StringComparison.CurrentCultureIgnoreCase)); + else + SelectedName = SourceNames.FirstOrDefault(); + } + finally + { + isServiceUpdating = false; + } } + private bool isServiceUpdating = false; + public void Dispose() { service.Changed -= OnServiceChanged; diff --git a/src/PackageManager/ViewModels/PackageViewModel.cs b/src/PackageManager/ViewModels/PackageViewModel.cs index 7e9295f..4abcdb4 100644 --- a/src/PackageManager/ViewModels/PackageViewModel.cs +++ b/src/PackageManager/ViewModels/PackageViewModel.cs @@ -77,7 +77,7 @@ public override bool Equals(object obj) if (other == null) return false; - return Id == other.Id && Version == other.Version; + return string.Equals(Id, other.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(Version, other.Version, StringComparison.CurrentCultureIgnoreCase); } public override int GetHashCode() diff --git a/test/PackageManager.NuGet.Tests/Services/InstallService.cs b/test/PackageManager.NuGet.Tests/Services/InstallService.cs index abf6ca3..afc0b1b 100644 --- a/test/PackageManager.NuGet.Tests/Services/InstallService.cs +++ b/test/PackageManager.NuGet.Tests/Services/InstallService.cs @@ -28,6 +28,7 @@ public static IInstallService Create(string extractPath) var frameworkFilter = new NuGetFrameworkFilter(frameworks); var packageFilter = new DependencyNuGetPackageFilter( + new DefaultLog(), new List() { new Args.Dependency("GitExtensions.Extensibility", null) diff --git a/test/PackageManager.NuGet.Tests/Services/SearchService.cs b/test/PackageManager.NuGet.Tests/Services/SearchService.cs index 69c2eea..c3ec8e4 100644 --- a/test/PackageManager.NuGet.Tests/Services/SearchService.cs +++ b/test/PackageManager.NuGet.Tests/Services/SearchService.cs @@ -28,6 +28,7 @@ public static (ISearchService search, IPackageSourceCollection sources) Create(s var frameworkFilter = new NuGetFrameworkFilter(frameworks); var packageFilter = new DependencyNuGetPackageFilter( + new DefaultLog(), new List() { new Args.Dependency("GitExtensions.Extensibility", null) @@ -45,10 +46,10 @@ public static (ISearchService search, IPackageSourceCollection sources) Create(s frameworkFilter ), new DependencyNuGetPackageFilter( + new DefaultLog(), new List() { new Args.Dependency("GitExtensions.Extensibility", null) }, frameworks - ), - new NuGetFrameworkFilter(frameworks) + ) ); EnsureConfigDeleted(configFilePath); diff --git a/test/PackageManager.NuGet.Tests/Services/TestInstallService.cs b/test/PackageManager.NuGet.Tests/Services/TestInstallService.cs index b5b6afc..eca910d 100644 --- a/test/PackageManager.NuGet.Tests/Services/TestInstallService.cs +++ b/test/PackageManager.NuGet.Tests/Services/TestInstallService.cs @@ -56,7 +56,7 @@ public void Install() Reader(reader => { - Assert.IsTrue(reader.GetPackages().Any(p => p.PackageIdentity.Id == package.Object.Id && p.PackageIdentity.Version.ToFullString() == package.Object.Version)); + Assert.IsTrue(reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, package.Object.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PackageIdentity.Version.ToFullString(), package.Object.Version, StringComparison.CurrentCultureIgnoreCase))); }); } @@ -69,7 +69,7 @@ public void UnInstall() Reader(reader => { - Assert.IsFalse(reader.GetPackages().Any(p => p.PackageIdentity.Id == package.Object.Id && p.PackageIdentity.Version.ToFullString() == package.Object.Version)); + Assert.IsFalse(reader.GetPackages().Any(p => string.Equals(p.PackageIdentity.Id, package.Object.Id, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PackageIdentity.Version.ToFullString(), package.Object.Version, StringComparison.CurrentCultureIgnoreCase))); }); }