OSDN Git Service

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