OSDN Git Service

na-get-lib,依存関係解決関数群を微修正
[applistation/AppliStation.git] / na-get-lib / NaGet.Packages.Install / DependeciesResolver.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Reflection;\r
4 \r
5 namespace NaGet.Packages.Install\r
6 {\r
7         /// <summary>\r
8         /// 依存関係を解決したりするための便利メソッド群\r
9         /// </summary>\r
10         public sealed class DependeciesResolver\r
11         {\r
12                 private DependeciesResolver()\r
13                 {\r
14                 }\r
15                 \r
16                 /// <summary>\r
17                 /// 依存解決済みInstallation配列を生成する\r
18                 /// </summary>\r
19                 /// <param name="insts">元のインストールリスト</param>\r
20                 /// <param name="pkgListsMan">インストール確認などをおこなうパッケージリストのマネージャ</param>\r
21                 /// <param name="resolved">解決済みInstallation配列</param>\r
22                 /// <param name="dependencies">依存によって必要とされたInstallation配列。ない場合は空配列</param>\r
23                 public static void ResolveInstallations(Installation[] insts, PackageListsManager pkgListsMan, out Installation[] resolved, out Installation[] dependencies)\r
24                 {\r
25                         List<Installation> depInsts;\r
26                         \r
27                         // 依存関係のインストールリスト\r
28                         depInsts = CreateRequiresInstallations(insts, pkgListsMan);\r
29                         dependencies = depInsts.ToArray();\r
30                         \r
31                         // 依存解決をしたインストールリスト\r
32                         depInsts.AddRange(insts);\r
33                         resolved = depInsts.ToArray();\r
34                 }\r
35                 \r
36                 /// <summary>\r
37                 /// Requires依存による依存パッケージの検索をし、それを解決するためのインストールリストを返す\r
38                 /// </summary>\r
39                 /// <param name="insts">対象インストールリスト</param>\r
40                 /// <param name="pkgListsMan">現在インストールされているか否かの判断に使われるパッケージリスト</param>\r
41                 /// <returns>Requires依存による依存</returns>\r
42                 public static List<Installation> CreateRequiresInstallations(Installation[] insts, PackageListsManager pkgListsMan)\r
43                 {\r
44                         List<Installation> reqInsts = new List<Installation>();\r
45                         \r
46                         foreach (Entry entry in DeleteDuplicatedEntries(CreateDependencyEntries(insts, "Requires"))) {\r
47                                 if (!pkgListsMan.IsInstalledFor(entry)) {                       \r
48                                         if (Array.Exists(insts, delegate(Installation inst) {\r
49                                                         return inst.InstalledPackage.Name == entry.Name;\r
50                                                          })) {\r
51                                                 continue;\r
52                                         } else {\r
53                                                 Package pkg = pkgListsMan.AvailablePkgList.GetPackageForEntry(entry);\r
54                                                 reqInsts.Add(new Installation(pkg));\r
55                                         }\r
56                                 }\r
57                         }\r
58                         \r
59                         return reqInsts;\r
60                 }\r
61                 \r
62                 /// <summary>\r
63                 /// 与えられたエントリのイテレータに対し、重複しているものを取り除いて返す\r
64                 /// </summary>\r
65                 /// <remarks>現段階の実装では、重複の判断は名前のみである</remarks>\r
66                 /// <param name="entries">エントリのイテレータ</param>\r
67                 /// <returns>重複しているものを取り除いたエントリのイテレータ</returns>\r
68                 private static IEnumerable<Entry> DeleteDuplicatedEntries(IEnumerable<Entry> entries)\r
69                 {\r
70                         LinkedList<string> pkgNames = new LinkedList<string>();\r
71                         \r
72                         foreach (Entry entry in entries) {\r
73                                 if (! pkgNames.Contains(entry.Name)) {\r
74                                         // 新出ならば返す\r
75                                         yield return entry;\r
76                                         pkgNames.AddFirst(entry.Name);\r
77                                 }\r
78                         }\r
79                 }\r
80                 \r
81                 /// <summary>\r
82                 /// 指定した依存エントリのイテレータを返す\r
83                 /// </summary>\r
84                 /// <remarks>現段階の実装では再帰的な依存は検索しない</remarks>\r
85                 /// <param name="insts">対象のインストールリスト</param>\r
86                 /// <param name="dependencyName">依存の種類名。<code>Package</code>クラスのフィールド名を入れる</param>\r
87                 /// <returns>依存エントリのイテレータ。重複に関して解決は行わない</returns>\r
88                 /// <exception cref="ArgumentException"><code>dependencyName</code>が不正であった場合</exception>\r
89                 public static IEnumerable<Entry> CreateDependencyEntries(Installation[] insts, string dependencyName)\r
90                 {\r
91                         FieldInfo depFInfo = null;\r
92                         \r
93                         try {\r
94                                 depFInfo = typeof(Installation).GetField(dependencyName, BindingFlags.Public);\r
95                                 if (depFInfo.FieldType != typeof(Installation[])) throw new ApplicationException("Field type does not Installation[].");\r
96                         } catch (Exception ex) {\r
97                                 throw new ArgumentException("Not suitable dependencyName", "dependencyName", ex);\r
98                         }\r
99                         \r
100                         foreach (Installation inst in insts) {\r
101                                 Entry[] deps = (Entry[]) depFInfo.GetValue(inst);\r
102                                 if (deps == null) continue;\r
103                                 foreach (Entry dep in deps) {\r
104                                         yield return dep;\r
105                                 }\r
106                         }\r
107                 }\r
108                 \r
109                 \r
110         }\r
111 }\r