using System;
using System.Collections.Generic;
using System.Reflection;
namespace NaGet.Packages.Install
{
///
/// 依存関係を解決したりするための便利メソッド群
///
public sealed class DependeciesResolver
{
private DependeciesResolver()
{
}
public static void ResolveInstallations(Installation[] insts, PackageListsManager pkgListsMan, out Installation[] resolved, out Installation[] dependencies)
{
List depInsts;
// 依存関係のインストールリスト
depInsts = CreateRequiresInstallations(insts, pkgListsMan);
dependencies = depInsts.ToArray();
// 依存解決をしたインストールリスト
depInsts.AddRange(insts);
resolved = depInsts.ToArray();
}
///
/// Requires依存による依存パッケージの検索をし、それを解決するためのインストールリストを返す
///
/// 対象インストールリスト
/// 現在インストールされているか否かの判断に使われるパッケージリスト
/// Requires依存による依存
public static List CreateRequiresInstallations(Installation[] insts, PackageListsManager pkgListsMan)
{
List reqInsts = new List();
foreach (Entry entry in CreateRequiresEntries(insts, pkgListsMan)) {
reqInsts.Add(new Installation(pkgListsMan.AvailablePkgList.GetPackageForEntry(entry)));
}
return reqInsts;
}
///
/// Requires依存による依存パッケージの検索をし、それをパッケージ参照エントリのイテレータで返す。
/// 返されるイテレータは、インストール済み及び重複のパッケージは取り除かれている。
///
/// 対象インストールリスト
/// 現在インストールされているか否かの判断に使われるパッケージリスト
/// Requires依存による依存
public static IEnumerable CreateRequiresEntries(Installation[] insts, PackageListsManager pkgListsMan)
{
foreach (Entry entry in DeleteDuplicatedEntries(CreateDependencyEntries(insts, "Requires"))) {
if (!pkgListsMan.IsInstalledFor(entry)) {
if (Array.Exists(insts, delegate(Installation inst) {
return inst.InstalledPackage.Name == entry.Name;
})) {
continue;
} else {
yield return entry;
}
}
}
}
///
/// 与えられたエントリのイテレータに対し、重複しているものを取り除いて返す
///
/// 現段階の実装では、重複の判断は名前のみである
/// エントリのイテレータ
/// 重複しているものを取り除いたエントリのイテレータ
private static IEnumerable DeleteDuplicatedEntries(IEnumerable entries)
{
List pkgNames = new List();
foreach (Entry entry in entries) {
if (pkgNames.IndexOf(entry.Name) < 0) {
// 新出ならば返す
yield return entry;
pkgNames.Add(entry.Name);
}
}
}
///
/// 指定した依存エントリのイテレータを返す
///
/// 現段階の実装では再帰的な依存は検索しない
/// 対象のインストールリスト
/// 依存の種類名。Package
クラスのフィールド名を入れる
/// 依存エントリのイテレータ。重複に関して解決は行わない
/// dependencyName
が不正であった場合
public static IEnumerable CreateDependencyEntries(Installation[] insts, string dependencyName)
{
FieldInfo depFInfo = null;
try {
depFInfo = typeof(Installation).GetField(dependencyName, BindingFlags.Public);
if (depFInfo.FieldType != typeof(Installation[])) throw new ApplicationException("Field type does not Installation[].");
} catch (Exception ex) {
throw new ArgumentException("Not suitable dependencyName", "dependencyName", ex);
}
foreach (Installation inst in insts) {
Entry[] deps = (Entry[]) depFInfo.GetValue(inst);
if (deps == null) continue;
foreach (Entry dep in deps) {
yield return dep;
}
}
}
}
}