using System;
using System.Collections.Generic;
using System.Reflection;
namespace NaGet.Packages.Install
{
///
/// 依存関係を解決したりするための便利メソッド群
///
public sealed class DependeciesResolver
{
private DependeciesResolver()
{
}
///
/// 依存解決済みInstallation配列を生成する
///
/// 元のインストールリスト
/// インストール確認などをおこなうパッケージリストのマネージャ
/// 解決済みInstallation配列
/// 依存によって必要とされたInstallation配列。ない場合は空配列
public static void ResolveInstallations(Installation[] insts, PackageListsManager pkgListsMan, out Installation[] resolved, out Installation[] dependencies)
{
List depInsts;
// 依存関係のインストールリスト
depInsts = CreateRequiresInstallations(insts, pkgListsMan, null);
dependencies = depInsts.ToArray();
// 依存解決をしたインストールリスト
depInsts.AddRange(insts);
resolved = depInsts.ToArray();
}
///
/// Requires依存による依存パッケージの検索をし、それを解決するためのインストールリストを返す
///
/// 対象インストールリスト
/// 現在インストールされているか否かの判断に使われるパッケージリスト
/// 優先して使用をするパッケージのリスト。nullでもよい
/// Requires依存による依存
public static List CreateRequiresInstallations(Installation[] insts, PackageListsManager pkgListsMan, ICollection preferencial)
{
List reqInsts = new List();
foreach (Entry entry in DeleteDuplicatedEntries(CreateRequiresEntries(insts))) {
List instPkgs = NaGet.Utils.MergeList(
pkgListsMan.installedPkgList.GetPackagesForEntry(entry),
pkgListsMan.systemInstalledPkgList.GetPackagesForEntry(entry)
);
if (instPkgs.Count <= 0) {
if (Array.Exists(insts, delegate(Installation inst) {
return entry.Match(inst.InstalledPackage);
})) {
continue;
} else {
VersionComparetor vc = new VersionComparetor();
Package pkgToBeInstall = null;
if (preferencial != null) {
foreach (Package pkg in preferencial) {
if (entry.Match(pkg)) {
pkgToBeInstall = pkg;
break;
}
}
}
if (pkgToBeInstall == null) {
foreach (Package pkg in pkgListsMan.availablePkgList.GetPackagesForEntry(entry)) {
if ((pkgToBeInstall == null) || (vc.Compare(pkgToBeInstall.Version, pkg.Version) < 0)) {
pkgToBeInstall = pkg;
}
}
}
if (pkgToBeInstall != null) {
reqInsts.Add(new Installation(pkgToBeInstall));
}
}
}
}
return reqInsts;
}
///
/// 与えられたエントリのイテレータに対し、重複しているものを取り除いて返す
///
/// 現段階の実装では、重複の判断は名前のみである
/// エントリのイテレータ
/// 重複しているものを取り除いたエントリのイテレータ
private static IEnumerable DeleteDuplicatedEntries(IEnumerable entries)
{
LinkedList pkgNames = new LinkedList();
foreach (Entry entry in entries) {
if (! pkgNames.Contains(entry.Name)) {
// 新出ならば返す
yield return entry;
pkgNames.AddFirst(entry.Name);
}
}
}
///
/// Requires依存エントリのイテレータを返す
///
/// 現段階の実装では再帰的な依存は検索しない
/// 対象のインストールリスト
/// 依存エントリのイテレータ。重複に関して解決は行わない
private static IEnumerable CreateRequiresEntries(Installation[] insts)
{
foreach (Installation inst in insts) {
Entry[] deps = inst.InstalledPackage.Requires;
if (deps == null) continue;
foreach (Entry dep in deps) {
yield return dep;
}
}
}
}
}