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;
}
}
}