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, null);\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                 /// <param name="preferencial">優先して使用をするパッケージのリスト。<c>null</c>でもよい</param>\r
42                 /// <returns>Requires依存による依存</returns>\r
43                 public static List<Installation> CreateRequiresInstallations(Installation[] insts, PackageListsManager pkgListsMan, ICollection<Package> preferencial)\r
44                 {\r
45                         List<Installation> reqInsts = new List<Installation>();\r
46                         \r
47                         foreach (Entry entry in DeleteDuplicatedEntries(CreateRequiresEntries(insts))) {\r
48                                 List<InstalledPackage> instPkgs = NaGet.Utils.MergeList<InstalledPackage>(\r
49                                         pkgListsMan.installedPkgList.GetPackagesForEntry(entry),\r
50                                         pkgListsMan.systemInstalledPkgList.GetPackagesForEntry(entry)\r
51                                 );\r
52                                 \r
53                                 if (instPkgs.Count <= 0) {\r
54                                         if (Array.Exists(insts, delegate(Installation inst) {\r
55                                                                 return entry.Match(inst.InstalledPackage);\r
56                                                          })) {\r
57                                                 continue;\r
58                                         } else {\r
59                                                 VersionComparetor vc = new VersionComparetor();\r
60                                                 Package pkgToBeInstall = null;\r
61                                                 \r
62                                                 if (preferencial != null) {\r
63                                                         foreach (Package pkg in preferencial) {\r
64                                                                 if (entry.Match(pkg)) {\r
65                                                                         pkgToBeInstall = pkg;\r
66                                                                         break;\r
67                                                                 }\r
68                                                         }\r
69                                                 }\r
70                                                 if (pkgToBeInstall == null) {\r
71                                                         foreach (Package pkg in pkgListsMan.availablePkgList.GetPackagesForEntry(entry)) {\r
72                                                                 if ((pkgToBeInstall == null) || (vc.Compare(pkgToBeInstall.Version, pkg.Version) < 0)) {\r
73                                                                         pkgToBeInstall = pkg;\r
74                                                                 }\r
75                                                         }\r
76                                                 }\r
77                                                 \r
78                                                 if (pkgToBeInstall != null) {\r
79                                                         reqInsts.Add(new Installation(pkgToBeInstall));\r
80                                                 }\r
81                                         }\r
82                                 }\r
83                         }\r
84                         \r
85                         return reqInsts;\r
86                 }\r
87                 \r
88                 /// <summary>\r
89                 /// 与えられたエントリのイテレータに対し、重複しているものを取り除いて返す\r
90                 /// </summary>\r
91                 /// <remarks>現段階の実装では、重複の判断は名前のみである</remarks>\r
92                 /// <param name="entries">エントリのイテレータ</param>\r
93                 /// <returns>重複しているものを取り除いたエントリのイテレータ</returns>\r
94                 private static IEnumerable<Entry> DeleteDuplicatedEntries(IEnumerable<Entry> entries)\r
95                 {\r
96                         LinkedList<string> pkgNames = new LinkedList<string>();\r
97                         \r
98                         foreach (Entry entry in entries) {\r
99                                 if (! pkgNames.Contains(entry.Name)) {\r
100                                         // 新出ならば返す\r
101                                         yield return entry;\r
102                                         pkgNames.AddFirst(entry.Name);\r
103                                 }\r
104                         }\r
105                 }\r
106                 \r
107                 /// <summary>\r
108                 /// Requires依存エントリのイテレータを返す\r
109                 /// </summary>\r
110                 /// <remarks>現段階の実装では再帰的な依存は検索しない</remarks>\r
111                 /// <param name="insts">対象のインストールリスト</param>\r
112                 /// <returns>依存エントリのイテレータ。重複に関して解決は行わない</returns>\r
113                 private static IEnumerable<Entry> CreateRequiresEntries(Installation[] insts)\r
114                 {\r
115                         foreach (Installation inst in insts) {\r
116                                 Entry[] deps = inst.InstalledPackage.Requires;\r
117                                 if (deps == null) continue;\r
118                                 foreach (Entry dep in deps) {\r
119                                         yield return dep;\r
120                                 }\r
121                         }\r
122                 }\r
123                 \r
124                 \r
125         }\r
126 }\r