using System; using System.Collections.Generic; using System.Collections.ObjectModel; using NaGet.Packages; using NaGet.Packages.Install; using NaGet.SubCommands; using NaGet.SubCommands.SubTask; using NaGet.Tasks; using NaGet.InteropServices; namespace NaGet.SubCommands { /// /// インストール処理 /// public class NaGetInstall2 : NaGetTaskSet2 { private IList installations; private DownloadScannerService scanner; private PackageListsManager pkgListMan; /// /// コンストラクタ /// /// インストールするパッケージ public NaGetInstall2(PackageListsManager pkgListMan, Package[] pkgs) : this(pkgListMan, Installation.ConvertInstallations(pkgs)) { } /// /// コンストラクタ /// /// インストール処理の配列 public NaGetInstall2(PackageListsManager pkgMan, IList insts) { pkgListMan = pkgMan; installations = new ReadOnlyCollection(insts); scanner = new DownloadScannerService(); scanner.Init(); initializeSubTasks(); } private void initializeSubTasks() { // taskセットの初期化 initSubTask(); foreach (Installation inst in installations) { VirusScanSubTask scanSTask = new VirusScanSubTask(scanner, inst.InstallerFile, inst.InstallerURL); if (! inst.Downloaded) { DownloadSubTask dlSTask = new DownloadSubTask(inst.InstallerURL, inst.InstallerFile); dlSTask.EnableChangeFileName = true; dlSTask.TaskEventRaised += delegate(object sender, TaskEventArgs e) { if (e.Type == TaskEventType.COMPLETED) { scanSTask.TargetFilePath = inst.InstallerFile = dlSTask.Filepath; } }; registSubTask(string.Format("ダウンロード: {0}", inst), dlSTask); } registSubTask(string.Format("ウイルススキャン: {0}", inst), scanSTask); } registSubTask("インストーラーの検証", new VerifyInstallerFileSubTask(installations)); foreach (Installation inst in installations) { bool isSilentInstall = (inst.Silent && inst.IsSupportsSilent); string msg = string.Format("インストール: {0}{1}", inst.ToString(), (isSilentInstall)? " (サイレントインストール)" : string.Empty); registSubTask(msg, new FunctionalSubTask(runInstall, inst)); } registSubTask("インストール済みのソフトリスト更新", new LocalUpdateSubTask(pkgListMan)); } public override void Run() { NotifyStarted(); RaiseTaskSetEvent(TaskEventType.STARTED, string.Empty); try { while (hasMoreSubTask) { bool canGoToNextSubTask = true; RaiseTaskSetEvent(TaskEventType.STARTED_SUBTASK, currentSubTaskName); currentSubTask.Run(); RaiseTaskSetEvent(TaskEventType.COMPLETED_SUBTASK, currentSubTaskName); if (runCheckVerify() == false) { canGoToNextSubTask = false; initializeSubTasks(); NotifyGoToSubTask(0); // 最初からやり直し。 } if (cancelCalled) { throw new TaskCanceledException("cancel is called"); } if (canGoToNextSubTask) { NotifyGoToNextSubTask(); } } } catch (TaskCanceledException) { cancelCalled = true; } catch (Exception e) { RaiseTaskSetEvent(TaskEventType.ERROR, e.Message); } if (cancelCalled) { NotifyCancelled(); RaiseTaskSetEvent(TaskEventType.CANCELED, "キャンセルされました"); } else { NotifyCompleted(); RaiseTaskSetEvent(TaskEventType.COMPLETED, string.Empty); } } private bool runCheckVerify() { bool ret = true; if (currentSubTask is VerifyInstallerFileSubTask) { VerifyInstallerFileSubTask verifySTask = currentSubTask as VerifyInstallerFileSubTask; if (verifySTask.InvalidInstallers != null && verifySTask.InvalidInstallers.Count > 0) { System.Text.StringBuilder invalidInstallerNames = new System.Text.StringBuilder(); foreach (Installation invalidInst in verifySTask.InvalidInstallers) { invalidInstallerNames.AppendFormat(" - {0}\n", invalidInst.ToString()); } string msg = string.Format("以下の{0}個のパッケージでファイルが壊れている可能性があります。\n{1}\n強制的にインストールを続行しますか?", verifySTask.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(TaskEventType.WARNING, "ハッシュの非整合を無視してインストールを継続"); ret = true; break; case NaGetTaskQueryResult.RETRY: RaiseTaskSetEvent(TaskEventType.INFO, "ダウンロード処理を再試行"); foreach (Installation invalidInst in verifySTask.InvalidInstallers) { invalidInst.RemoveDownloadedFile(); } ret = false; break; case NaGetTaskQueryResult.CANCEL: case NaGetTaskQueryResult.CANCELED_AUTOMATICALLY: default: ret = false; throw new TaskCanceledException("処理の継続のキャンセルが選択されました"); } } } return ret; } private void runInstall(Installation inst) { if (! inst.IsInstallablePackage()) { string msg = string.Format("{0}はインストールすることができません", inst.ToString()); throw new ApplicationException(msg); } inst.ErrorDataReceived += this.ReceivedErrorData; inst.OutputDataReceived += this.ReceivedOutputData; int exitCode = inst.Install(); if (exitCode != 0) { RaiseTaskSetEvent(TaskEventType.WARNING, "インストールが正常に終えていない可能性があります。プロセスの終了コード:"+exitCode); } pkgListMan.WriteInstallationLog(inst); } public override bool Cancelable { get { return !cancelCalled && Running && isDuringDownloading; } } private bool isDuringDownloading { get { return Running && (currentSubTask is DownloadSubTask); } } } }