OSDN Git Service

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