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);
    }
Example #3
0
    /// <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);
    }
}
Example #4
0
    /// <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);
    }
}
Example #5
0
    /// <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);
    }
Example #8
0
    /// <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);
    }
Example #9
0
    /// <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);
    }