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