using System; using System.Collections.Generic; using NaGet.Packages.Install; using NaGet.Packages; using NaGet.Net; namespace NaGet.SubCommands { public class NaGetInstall : NaGetTaskSet { private bool done = false; private int currentTaskSetIndex = -1; private PackageListsManager pkgListMan; /// /// ダウンロードに使うダウンローダオブジェクト /// public Downloader Downloader { get { if (downloader == null) { downloader = new Downloader(); downloader.DownloadEventRaised += delegate(object sender, DownloadEventArgs e) { if (e.Type == DownloadEventType.DOWNLOADING && e.TaskProgressPercent > 0) { RaiseTaskSetEvent(NaGetTaskSetEventType.PING, string.Empty, GetProgressPercent(NaGetTaskSetEventType.PING, e.TaskProgressPercent)); } }; } return downloader; } } private Downloader downloader; private bool packageInstallerDownloaded = false; public override bool Cancelable { get { return ! done; } } /// /// インストールするパッケージ /// public Installation[] Installations; /// /// コンストラクタ /// /// インストールするパッケージ public NaGetInstall(PackageListsManager pkgListMan, Package[] pkgs) : this(pkgListMan, Installation.ConvertInstallations(pkgs)) { } /// /// コンストラクタ /// /// インストール処理の配列 public NaGetInstall(PackageListsManager pkgMan, Installation[] installations) { pkgListMan = pkgMan; Installations = installations; initializeMainTaskSetNames(); } private void initializeMainTaskSetNames() { List taskSetNames = new List(); for (int i =0; i < Installations.Length; i++) { taskSetNames.Add(string.Format("取得: {0}", Installations[i].ToString())); taskSetNames.Add(string.Format("ウイルススキャン: {0}", Installations[i].ToString())); } taskSetNames.Add("インストーラーの検証"); for (int i =0; i < Installations.Length; i++) { taskSetNames.Add(string.Format("インストール: {0}", Installations[i].ToString())); } taskSetNames.Add(string.Format("リスト更新: {0}", NaGet.Env.ArchiveInstalledPackageListFile)); taskSetNames.Add(string.Format("リスト更新: {0}", NaGet.Env.SystemInstalledPackageListFile)); TaskSetNames = taskSetNames.ToArray(); } public override void Run() { currentTaskSetIndex = 0; RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED, "インストール処理開始"); { // ハッシュ非適合なインストーラの表 List invalidInstallers = null; do { currentTaskSetIndex = 0; packageInstallerDownloaded = false; runDownloadAndVirusCheckInstallers(); if (done) return; // もしrunDownloadInstallers()内でエラー終了していたなら終了 packageInstallerDownloaded = true; RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]); // ハッシュの壊れているインストーラーを取得 invalidInstallers = runCheckHashForInstaller(); // ハッシュが壊れているときの対策 if (invalidInstallers.Count > 0) { System.Text.StringBuilder invalidInstallerNames = new System.Text.StringBuilder(); foreach (Installation invalidInst in invalidInstallers) { invalidInstallerNames.AppendFormat(" - {0}\n", invalidInst.ToString()); } string msg = string.Format("以下の{0}個のパッケージでファイルが壊れている可能性があります。\n{1}\n強制的にインストールを続行しますか?", invalidInstallers.Count, invalidInstallerNames.ToString()); NaGetTaskQueryResult result = NaGetTaskQueryResult.CANCEL; if (!cancelCalled) { result = RaiseTaskSetQueryEvent(msg, NaGetTaskQueryResult.CONTINUE | NaGetTaskQueryResult.RETRY | NaGetTaskQueryResult.CANCEL); } switch (result) { case NaGetTaskQueryResult.CONTINUE: RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "ハッシュの非整合を無視してインストールを継続"); invalidInstallers.Clear(); // ハッシュ非適合パッケージを強制的に抹消 break; case NaGetTaskQueryResult.RETRY: RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "ダウンロード処理を再試行"); foreach (Installation invalidInst in invalidInstallers) { invalidInst.RemoveDownloadedFile(); } break; //case NaGetTaskQueryResult.CANCEL: default: RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました"); done = true; return; } } // もしハッシュが不適合なソフトがあるならばダウンロード処理からやり直す } while (invalidInstallers == null || invalidInstallers.Count > 0); RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]); currentTaskSetIndex ++; } foreach (Installation inst in Installations) { string installTaskMsg = TaskSetNames[currentTaskSetIndex]; if (inst.Silent && (!inst.SupportsSilentOnly)) { installTaskMsg += " (サイレントインストール)"; } RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, installTaskMsg); try { inst.ErrorDataReceived += this.ReceivedErrorData; inst.OutputDataReceived += this.ReceivedOutputData; int exitCode = inst.Install(); if (exitCode != 0) { RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "インストールが正常に終えていない可能性があります。プロセスの終了コード:"+exitCode); } pkgListMan.WriteInstallationLog(inst); } catch (Exception e) { RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, e.Message); done = true; return; } RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, installTaskMsg); currentTaskSetIndex ++; if (cancelCalled) { RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました"); done = true; return; } } runLocalUpdate(); done = true; RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED, "終了", 100); } /// /// 処理内容のダウンロード・ウイルススキャン部分のサブルーチン /// private void runDownloadAndVirusCheckInstallers() { using (DownloadScanner scanner = new DownloadScanner()) { scanner.Init(); foreach (Installation inst in Installations) { if (! inst.IsInstallablePackage()) { string msg = string.Format("{0}はインストールすることができません", inst.ToString()); RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, msg); done = true; return; } RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]); if (! inst.Downloaded) { try { inst.Download(Downloader); } catch (NaGetTaskCanceledException) { RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "インストーラーのダウンロード処理がキャンセルされました"); done = true; return; } catch (System.Net.WebException e) { RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, e.Message); if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) { RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "ネットワークに接続されていません。"); } else { RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "ネットワークに接続できませんでした。ネットワークが切断されているか、ファイアウォールによって遮断された可能性があります。"); } done = true; return; } catch (Exception e) { RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, e.Message); done = true; return; } } if (! inst.Downloaded) { // ダウンロードが完了せずに終わった=失敗=エラー RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, string.Format("{0}のインストーラーファイルを正常にダウンロードできませんでした", inst.ToString())); done = true; return; } RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]); currentTaskSetIndex ++; RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]); if (! NaGet.Env.EnableScanInstallerFile) { RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "ウイルススキャンを行わない設定のため、ダウンロードしたファイルはウイルススキャンされませんでした"); } else if (!scanner.HasScanner) { RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "ダウンロードしたファイルはウイルススキャンされませんでした(ウイルススキャンソフトが検出できませんでした)"); } else { try { DownloadScannerResult result = inst.ScanInstallerFile(scanner); switch (result) { case DownloadScannerResult.ScannerNotFound: RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "ダウンロードしたファイルはウイルススキャンされませんでした(ウイルススキャンソフトが検出できませんでした)"); break; case DownloadScannerResult.InfectedAndCleaned: RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "インストーラーファイルからウイルス感染が検出されたため、削除されました。"); done = true; return; case DownloadScannerResult.InfectedButNotCleaned: RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "インストーラーファイルからウイルス感染が検出されました。"); done = true; break; case DownloadScannerResult.ErrorNotFound: throw new System.IO.FileNotFoundException(string.Empty); //break; } } catch (System.Runtime.InteropServices.COMException ex) { RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, string.Format("{0} (E{1})", ex.Message, ex.ErrorCode)); } catch (System.IO.FileNotFoundException ex) { if (ex.InnerException is System.Runtime.InteropServices.COMException) { RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, string.Format("{0} (E{1})", ex.InnerException.Message, ((System.Runtime.InteropServices.COMException) ex.InnerException).ErrorCode)); } RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "インストーラーファイルがウイルススキャナーによって削除されました。"); done = true; return; } } RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]); currentTaskSetIndex ++; if (cancelCalled) { RaiseTaskSetEvent(NaGetTaskSetEventType.CANCELED, "パッケージのインストール処理がキャンセルされました"); done = true; return; } } } } /// /// ダウンロードしたパッケージが整合したか否かハッシュでチェック /// /// 整合しなかったインストーラーのリスト private List runCheckHashForInstaller() { List invalidInstallers = new List(); int i = 0; foreach (Installation inst in Installations) { float percent = (CurrentTaskSetIndex+((float)i / Installations.Length))*100f/TaskSetNames.Length; if (inst.GetRegisteredHashCount() > 0) { RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "検証: "+inst.ToString(), percent); if (inst.IsInstallablePackage() && inst.VerifyHashValues() == false) { invalidInstallers.Add(inst); RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING, "検証: "+inst.ToString() + " 非整合", percent); } else { RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, "検証: "+inst.ToString() + " OK", percent); } } i++; } return invalidInstallers; } private void runLocalUpdate() { // インストールトリストの更新 RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]); pkgListMan.DetectInstalledPkgs(); pkgListMan.SaveInstalledPackageList(); RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]); currentTaskSetIndex++; // システムにインストールされているリストの更新 RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]); pkgListMan.DetectSystemInstalledPkgs(); pkgListMan.SaveSystemInstalledPackageList(); RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]); currentTaskSetIndex++; } public override bool Done { get { return done; } } public override int CurrentTaskSetIndex { get { return currentTaskSetIndex; } } private bool cancelCalled = false; public override bool Cancel() { cancelCalled = true; if (! packageInstallerDownloaded) { return Downloader.Cancel(); } else return true; } } }