public void Combine_ReturnsNoDuplicates() { const string id = "mod.duplicate.id"; const string idNonExist = "mod.nonexist.id"; var resultOld = new ModDependencyResolveResult(); resultOld.FoundDependencies.Add(new DummyDownloadablePackage() { Id = id }); resultOld.NotFoundDependencies.Add(idNonExist); var resultNew = new ModDependencyResolveResult(); resultNew.FoundDependencies.Add(new DummyDownloadablePackage() { Id = id }); resultNew.NotFoundDependencies.Add(idNonExist); // Act var resultCombined = ModDependencyResolveResult.Combine(new[] { resultOld, resultNew }); // Assert Assert.Single(resultCombined.FoundDependencies); Assert.Single(resultCombined.NotFoundDependencies); }
public void Combine_ReturnsLatestVersion() { const string id = "mod.duplicate.id"; var oldVersion = NuGetVersion.Parse("1.0.0"); var newVersion = NuGetVersion.Parse("1.0.1"); var resultOld = new ModDependencyResolveResult(); resultOld.FoundDependencies.Add(new DummyDownloadablePackage() { Id = id, Version = oldVersion }); var resultNew = new ModDependencyResolveResult(); resultNew.FoundDependencies.Add(new DummyDownloadablePackage() { Id = id, Version = newVersion }); // Act var resultCombined = ModDependencyResolveResult.Combine(new[] { resultOld, resultNew }); // Assert Assert.Single(resultCombined.FoundDependencies); Assert.Equal(newVersion, resultCombined.FoundDependencies[0].Version); }
/// <inheritdoc /> public async Task <ModDependencyResolveResult> ResolveAsync(string packageId, Dictionary <string, object>?pluginData = null, CancellationToken token = default) { // If no mod config is provided, we cannot resolve. if (pluginData == null) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; // If no dependency data is available, return none. if (!pluginData.TryGetValue(GitHubReleasesDependencyMetadataWriter.PluginId, out DependencyResolverMetadata <GitHubReleasesUpdateResolverFactory.GitHubConfig> metadata)) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; // Try to get configuration for update. if (!metadata.IdToConfigMap.TryGetValue(packageId, out var gitConfig)) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; var result = new ModDependencyResolveResult(); var resolver = new GitHubReleaseResolver(new GitHubResolverConfiguration() { UserName = gitConfig.Config.UserName, RepositoryName = gitConfig.Config.RepositoryName, LegacyFallbackPattern = gitConfig.Config.AssetFileName, InheritVersionFromTag = gitConfig.Config.UseReleaseTag }, new CommonPackageResolverSettings() { MetadataFileName = gitConfig.ReleaseMetadataName }); await((IPackageResolver)resolver).InitializeAsync(); result.FoundDependencies.Add(new UpdateDownloadablePackage(resolver) { Id = packageId }); return(result); } }
/// <inheritdoc /> public async Task <ModDependencyResolveResult> ResolveAsync(string packageId, Dictionary <string, object>?pluginData = null, CancellationToken token = default) { // If no mod config is provided, we cannot resolve. if (pluginData == null) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; // If no dependency data is available, return none. if (!pluginData.TryGetValue(GameBananaDependencyMetadataWriter.PluginId, out DependencyResolverMetadata <GameBananaUpdateResolverFactory.GameBananaConfig> metadata)) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; // Try to get configuration for update. if (!metadata.IdToConfigMap.TryGetValue(packageId, out var gbConfig)) { return new ModDependencyResolveResult() { NotFoundDependencies = { packageId } } } ; var result = new ModDependencyResolveResult(); var resolver = new GameBananaUpdateResolver(new GameBananaResolverConfiguration() { ItemId = (int)gbConfig.Config.ItemId, ModType = gbConfig.Config.ItemType }, new CommonPackageResolverSettings() { MetadataFileName = gbConfig.ReleaseMetadataName }); await resolver.InitializeAsync(); result.FoundDependencies.Add(new UpdateDownloadablePackage(resolver) { Id = packageId }); return(result); } }
/// <summary> /// Resolves a list of missing packages. /// </summary> /// <param name="token">Used to cancel the operation.</param> public static async Task ResolveMissingPackagesAsync(CancellationToken token = default) { if (!HasInternetConnection) { return; } ModDependencyResolveResult resolveResult = null !; do { // Get missing dependencies for this update loop. var missingDeps = CheckMissingDependencies(); // Get Dependencies var resolver = DependencyResolverFactory.GetInstance(IoC.Get <AggregateNugetRepository>()); var results = new List <Task <ModDependencyResolveResult> >(); foreach (var dependencyItem in missingDeps.Items) { foreach (var dependency in dependencyItem.Dependencies) { results.Add(resolver.ResolveAsync(dependency, dependencyItem.Mod.PluginData, token)); } } await Task.WhenAll(results); // Merge Results resolveResult = ModDependencyResolveResult.Combine(results.Select(x => x.Result)); DownloadPackages(resolveResult, token); }while (resolveResult.FoundDependencies.Count > 0); if (resolveResult.NotFoundDependencies.Count > 0) { ActionWrappers.ExecuteWithApplicationDispatcher(() => { Actions.DisplayMessagebox(Resources.ErrorMissingDependency.Get(), $"{Resources.FetchNugetNotFoundMessage.Get()}\n\n" + $"{string.Join('\n', resolveResult.NotFoundDependencies)}\n\n" + $"{Resources.FetchNugetNotFoundAdvice.Get()}", new Actions.DisplayMessageBoxParams() { Type = Actions.MessageBoxType.Ok, StartupLocation = Actions.WindowStartupLocation.CenterScreen }); }); } }
/// <inheritdoc /> public async Task <ModDependencyResolveResult> ResolveAsync(string packageId, Dictionary <string, object>?pluginData = null, CancellationToken token = default) { // Run parallel resolve operations var tasks = new Task <ModDependencyResolveResult> [_resolvers.Length]; for (var x = 0; x < _resolvers.Length; x++) { tasks[x] = _resolvers[x].ResolveAsync(packageId, pluginData, token); } await Task.WhenAll(tasks); // Merge results. var result = new ModDependencyResolveResult(); var packageToVersionMap = new Dictionary <string, IDownloadablePackage>(); foreach (var task in tasks) { // Merge found dependencies foreach (var dependency in task.Result.FoundDependencies) { if (dependency.Id == null) { continue; } if (!packageToVersionMap.TryGetValue(dependency.Id, out var existing)) { packageToVersionMap[dependency.Id] = dependency; continue; } if (dependency.Version > existing.Version) { packageToVersionMap[dependency.Id] = dependency; } } // Merge not found dependencies. foreach (var notFound in task.Result.NotFoundDependencies) { result.NotFoundDependencies.Add(notFound); } } result.FoundDependencies.AddRange(packageToVersionMap.Values); return(result); }
/// <inheritdoc /> public async Task <ModDependencyResolveResult> ResolveAsync(string packageId, Dictionary <string, object>?pluginData = null, CancellationToken token = default) { var searchResult = await _repository.FindDependencies(packageId, true, true, token); var result = new ModDependencyResolveResult(); foreach (var dependency in searchResult.Dependencies) { var package = dependency.Generic; var repository = dependency.Repository; result.FoundDependencies.Add(await WebDownloadablePackage.FromNuGetAsync(package, repository)); } foreach (var notFound in searchResult.PackagesNotFound) { result.NotFoundDependencies.Add(notFound); } return(result); }
/// <summary> /// Shows the dialog for downloading dependencies given a result of dependency resolution. /// </summary> /// <param name="resolveResult">Result of resolving for missing packages.</param> /// <param name="token">Used to cancel the operation.</param> public static void DownloadPackages(ModDependencyResolveResult resolveResult, CancellationToken token = default) { if (!HasInternetConnection) { return; } if (resolveResult.FoundDependencies.Count <= 0) { return; } var viewModel = new DownloadPackageViewModel(resolveResult.FoundDependencies, IoC.Get <LoaderConfig>()); viewModel.Text = Resources.PackageDownloaderDownloadingDependencies.Get(); #pragma warning disable CS4014 viewModel.StartDownloadAsync(); // Fire and forget. #pragma warning restore CS4014 Actions.SynchronizationContext.Send(state => { Actions.ShowFetchPackageDialog.Invoke(viewModel); }, null); }
/// <summary> /// Combines the results of multiple resolve operations. /// </summary> /// <param name="results">Results of multiple operations.</param> /// <returns>The result of combining multiple resolve operations.</returns> public static ModDependencyResolveResult Combine(IEnumerable <ModDependencyResolveResult> results) { var returnValue = new ModDependencyResolveResult(); var idToNewestVersion = new Dictionary <string, IDownloadablePackage>(); foreach (var result in results) { foreach (var found in result.FoundDependencies) { if (found.Id == null) { continue; } if (idToNewestVersion.TryGetValue(found.Id, out var existing)) { if (existing.Version < found.Version) { idToNewestVersion[found.Id] = found; } continue; } idToNewestVersion[found.Id] = found; } foreach (var notFound in result.NotFoundDependencies) { returnValue.NotFoundDependencies.Add(notFound); } } returnValue.FoundDependencies.AddRange(idToNewestVersion.Values); return(returnValue); }