OSDN Git Service

a3e5e31866b744a017019d1776f88a5208a51b07
[applistation/AppliStation.git] / na-get-lib / NaGet.SubCommands / NaGetInstall.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using NaGet.Packages.Install;\r
4 using NaGet.Packages;\r
5 using NaGet.Net;\r
6 \r
7 namespace NaGet.SubCommands\r
8 {\r
9         public class NaGetInstall : NaGetTaskSet\r
10         {\r
11                 private bool done = false;\r
12                 \r
13                 private int currentTaskSetIndex = -1;\r
14                 \r
15                 private PackageListsManager pkgListMan;\r
16                 \r
17                 /// <summary>\r
18                 /// ダウンロードに使うダウンローダオブジェクト\r
19                 /// </summary>\r
20                 public Downloader Downloader {\r
21                         get {\r
22                                 if (downloader == null) {\r
23                                         downloader = new Downloader();\r
24                                 }\r
25                                 return downloader;\r
26                         }\r
27                 }\r
28                 \r
29                 private Downloader downloader;\r
30                 \r
31                 private bool packageInstallerDownloaded = false;\r
32                 \r
33                 public override bool Cancelable {\r
34                         get { return ! done; }\r
35                 }\r
36                 \r
37                 /// <summary>\r
38                 /// インストールするパッケージ\r
39                 /// </summary>\r
40                 public Installation[] Installations;\r
41                 \r
42                 /// <summary>\r
43                 /// コンストラクタ\r
44                 /// </summary>\r
45                 /// <param name="pkgs">インストールするパッケージ</param>\r
46                 public NaGetInstall(PackageListsManager pkgListMan, Package[] pkgs)\r
47                         : this(pkgListMan, Installation.ConvertInstallations(pkgs))\r
48                 {\r
49                 }\r
50                 \r
51                 /// <summary>\r
52                 /// コンストラクタ\r
53                 /// </summary>\r
54                 /// <param name="installations">インストール処理の配列</param>\r
55                 public NaGetInstall(PackageListsManager pkgMan, Installation[] installations)\r
56                 {\r
57                         pkgListMan = pkgMan;\r
58                         \r
59                         Installations = installations;\r
60                         initializeMainTaskSetNames();\r
61                 }\r
62                 \r
63                 private void initializeMainTaskSetNames()\r
64                 {\r
65                         List<string> taskSetNames = new List<string>();\r
66                         \r
67                         for (int i =0; i < Installations.Length; i++) {\r
68                                 taskSetNames.Add(string.Format("取得: {0}", Installations[i].ToString()));\r
69                                 taskSetNames.Add(string.Format("ウイルススキャン: {0}", Installations[i].ToString()));\r
70                         }\r
71                         taskSetNames.Add("インストーラの検証");\r
72                         for (int i =0; i < Installations.Length; i++) {\r
73                                 taskSetNames.Add(string.Format("インストール: {0}", Installations[i].ToString()));\r
74                         }\r
75                         taskSetNames.Add(string.Format("リスト更新: {0}", NaGet.Env.ArchiveInstalledPackageListFile));\r
76                         taskSetNames.Add(string.Format("リスト更新: {0}", NaGet.Env.SystemInstalledPackageListFile));\r
77                         \r
78                         TaskSetNames = taskSetNames.ToArray();\r
79                 }\r
80                                 \r
81                 public override void Run()\r
82                 {\r
83                         currentTaskSetIndex = 0;\r
84                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED, "インストール処理開始");\r
85                         \r
86                         {\r
87                                 // ハッシュ非適合なインストーラの表\r
88                                 List<Installation> invalidInstallers = null;\r
89                                 \r
90                                 while (invalidInstallers == null || invalidInstallers.Count > 0) {\r
91                                         currentTaskSetIndex = 0;\r
92                                         packageInstallerDownloaded = false;\r
93                                         \r
94                                         runDownloadAndVirusCheckInstallers();\r
95                                         if (done) return; // もしrunDownloadInstallers()内でエラー終了していたなら終了\r
96                                         \r
97                                         packageInstallerDownloaded = true;\r
98                                         \r
99                                         \r
100                                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
101                                         \r
102                                         // ハッシュの壊れているインストーラを取得\r
103                                         invalidInstallers = runCheckHashForInstaller();\r
104                                         \r
105                                         // ハッシュが壊れているときの対策\r
106                                         if (invalidInstallers.Count > 0) {\r
107                                                 string msg = string.Format("{0}個のパッケージでファイルが壊れている可能性があります\n強制的にインストールを続行しますか?",\r
108                                                                            invalidInstallers.Count);\r
109                                                 NaGetTaskQueryResult result = NaGetTaskQueryResult.CANCEL;\r
110                                                 \r
111                                                 if (!cancelCalled) {\r
112                                                         result = RaiseTaskSetQueryEvent(msg, NaGetTaskQueryResult.CONTINUE\r
113                                                                                         | NaGetTaskQueryResult.RETRY\r
114                                                                                         | NaGetTaskQueryResult.CANCEL);\r
115                                                 }\r
116                                                 \r
117                                                 switch (result) {\r
118                                                         case NaGetTaskQueryResult.CONTINUE:\r
119                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "ハッシュの非整合を無視してインストールを継続");\r
120                                                                 invalidInstallers.Clear(); // ハッシュ非適合パッケージを強制的に抹消\r
121                                                                 break;\r
122                                                         case NaGetTaskQueryResult.RETRY:\r
123                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "ダウンロード処理を再試行");\r
124                                                                 \r
125                                                                 foreach (Installation invalidInst in invalidInstallers) {\r
126                                                                         invalidInst.RemoveDownloadedFile();\r
127                                                                 }\r
128                                                                 \r
129                                                                 break;\r
130                                                         //case NaGetTaskQueryResult.CANCEL:\r
131                                                         default:\r
132                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました");\r
133                                                                 done = true;\r
134                                                                 return;\r
135                                                 }\r
136                                         }\r
137                                         currentTaskSetIndex ++;\r
138                                         RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex-1]);\r
139                                 }\r
140                         }\r
141                         \r
142                         foreach (Installation inst in Installations) {\r
143                                 string installTaskMsg = TaskSetNames[currentTaskSetIndex];\r
144                                 if (inst.Silent && (!inst.SupportsSilentOnly)) {\r
145                                         installTaskMsg += " (サイレントインストール)";\r
146                                 }\r
147                                 \r
148                                 RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, installTaskMsg);\r
149                                 \r
150                                 try {\r
151                                         \r
152                                         inst.ErrorDataReceived += this.ReceivedErrorData;\r
153                                         inst.OutputDataReceived += this.ReceivedOutputData;\r
154                                         int exitCode = inst.Install();\r
155                                         if (exitCode != 0) {\r
156                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "インストールが正常に終えていない可能性があります。インストーラの終了コード:"+exitCode);\r
157                                         }\r
158                                         \r
159                                         pkgListMan.WriteInstallationLog(inst);\r
160                                 } catch (Exception e) {\r
161                                         RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, e.Message);\r
162                                         done = true;\r
163                                         return;\r
164                                 }\r
165                                 currentTaskSetIndex ++;\r
166                                 \r
167                                 RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, installTaskMsg);\r
168                                 \r
169                                 if (cancelCalled) {\r
170                                         RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました");\r
171                                         done = true;\r
172                                         return;\r
173                                 }\r
174                         }\r
175                         pkgListMan.SaveSystemInstalledLogList(); // ログのコミット\r
176                         \r
177                         runLocalUpdate();\r
178                         \r
179                         done = true;\r
180                         \r
181                         RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED, "終了", 100);\r
182                 }\r
183                 \r
184                 \r
185                 /// <summary>\r
186                 /// 処理内容のダウンロード・ウイルススキャン部分のサブルーチン\r
187                 /// </summary>\r
188                 private void runDownloadAndVirusCheckInstallers()\r
189                 {\r
190                         using (DownloadScanner scanner = new DownloadScanner()) {\r
191                                 scanner.Init();\r
192                                 foreach (Installation inst in Installations) {\r
193                                         if (! inst.IsInstallablePackage()) {\r
194                                                 string msg = string.Format("{0}はインストールすることができません", inst.ToString());\r
195                                                 \r
196                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, msg);\r
197                                                 done = true;\r
198                                                 return;\r
199                                         }\r
200                                         \r
201                                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
202                                         \r
203                                         if (! inst.Downloaded) {\r
204                                                 try {\r
205                                                         inst.Download(Downloader);\r
206                                                 } catch (NaGetTaskCanceledException) {\r
207                                                         RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "インストーラのダウンロード処理がキャンセルされました");\r
208                                                         done = true;\r
209                                                         return;\r
210                                                 } catch (System.Net.WebException e) {\r
211                                                         RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, e.Message);\r
212                                                         if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) {\r
213                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "ネットワークに接続されていません。");\r
214                                                         } else {\r
215                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "ネットワークに接続できませんでした。ネットワークが切断されているか、ファイアウォールによって遮断された可能性があります。");\r
216                                                         }\r
217                                                         done = true;\r
218                                                         return;\r
219                                                 } catch (Exception e) {\r
220                                                         RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, e.Message);\r
221                                                         done = true;\r
222                                                         return;\r
223                                                 }\r
224                                         }\r
225                                         currentTaskSetIndex ++;\r
226                                         \r
227                                         if (inst.Downloaded) { // 正常終了\r
228                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex-1]);\r
229                                         } else { // インストールが完了せずに終わった=失敗=エラー\r
230                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, string.Format("{0}のインストーラを正常にダウンロードできませんでした", inst.ToString()));\r
231                                                 done = true;\r
232                                                 return;\r
233                                         }\r
234                                         \r
235                                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
236                                         if (scanner.HasScanner) {\r
237                                                 try {\r
238                                                         inst.ScanInstallerFile(scanner);\r
239                                                 } catch (System.Runtime.InteropServices.COMException ex) {\r
240                                                         RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING,\r
241                                                                           string.Format("{0} (E{1})", ex.Message, ex.ErrorCode));\r
242                                                 } catch (System.IO.FileNotFoundException ex) {\r
243                                                         if (ex.InnerException is System.Runtime.InteropServices.COMException) {\r
244                                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING,\r
245                                                                                   string.Format("{0} (E{1})", ex.InnerException.Message, ((System.Runtime.InteropServices.COMException) ex.InnerException).ErrorCode));\r
246                                                         }\r
247                                                         RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "インストーラがウイルススキャナによって削除されました。");\r
248                                                         done = true;\r
249                                                         return;\r
250                                                 }\r
251                                         } else {\r
252                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, string.Format("ダウンロードしたファイルはウイルススキャンされませんでした(ウイルススキャンソフトが検出できませんでした)"));\r
253                                         }\r
254                                         currentTaskSetIndex ++;\r
255                                         RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex-1]);\r
256                                         \r
257                                         if (cancelCalled) {\r
258                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました");\r
259                                                 done = true;\r
260                                                 return;\r
261                                         }\r
262                                 }\r
263                         }\r
264                 }\r
265                 \r
266                 /// <summary>\r
267                 /// ダウンロードしたパッケージが整合したか否かハッシュでチェック\r
268                 /// </summary>\r
269                 /// <returns>整合しなかったインストーラのリスト</returns>\r
270                 private List<Installation> runCheckHashForInstaller()\r
271                 {\r
272                         List<Installation> invalidInstallers = new List<Installation>();\r
273                         \r
274                         int i = 0;\r
275                         foreach (Installation inst in Installations) {\r
276                                 float percent = (CurrentTaskSetIndex+((float)i / Installations.Length))*100f/TaskSetNames.Length;\r
277                                 \r
278                                 if (inst.GetRegisteredHashCount() > 0) {\r
279                                         RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "検証: "+inst.ToString(), percent);\r
280                                         \r
281                                         if (inst.IsInstallablePackage() && inst.VerifyHashValues() == false) {\r
282                                                 invalidInstallers.Add(inst);\r
283                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "検証: "+inst.ToString() + " 非整合", percent);\r
284                                         } else {\r
285                                                 RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "検証: "+inst.ToString() + " OK", percent);\r
286                                         }\r
287                                 }\r
288                                 i++;\r
289                         }\r
290                         \r
291                         return invalidInstallers;\r
292                 }\r
293                 \r
294                 private void runLocalUpdate()\r
295                 {\r
296                         // インストールトリストの更新\r
297                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
298                         pkgListMan.DetectInstalledPkgs();\r
299                         pkgListMan.SaveInstalledPackageList();\r
300                         currentTaskSetIndex++;\r
301                         RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex-1]);\r
302                 \r
303                         // システムにインストールされているリストの更新\r
304                         RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
305                         pkgListMan.DetectSystemInstalledPkgs();\r
306                         pkgListMan.SaveSystemInstalledPackageList();\r
307                         currentTaskSetIndex++;\r
308                         RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex-1]);\r
309                 }\r
310                 \r
311                 public override bool Done {\r
312                         get { return done; }\r
313                 }\r
314                 \r
315                 public override int CurrentTaskSetIndex {\r
316                         get { return currentTaskSetIndex; }\r
317                 }\r
318                 \r
319                 private bool cancelCalled = false;\r
320                 \r
321                 public override bool Cancel()\r
322                 {\r
323                         cancelCalled = true;\r
324                         if (! packageInstallerDownloaded) {\r
325                                 return Downloader.Cancel();\r
326                         } else return true;\r
327                 }\r
328         }\r
329 }\r