OSDN Git Service

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