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; } } } } }