OSDN Git Service

AppliStation-all,単体の実行ファイルのインストール対応
[applistation/AppliStation.git] / na-get-lib / NaGet.Packages.Install / Installation.cs
index 9711c93..de5d2a1 100644 (file)
@@ -3,6 +3,7 @@ using System.IO;
 using System.Diagnostics;\r
 using NaGet.Net;\r
 using NaGet.SubCommands;\r
+using System.Xml.Serialization;\r
 \r
 namespace NaGet.Packages.Install\r
 {\r
@@ -12,15 +13,25 @@ namespace NaGet.Packages.Install
     /// </summary>\r
     public class Installation\r
        {\r
+               private Package installedPackage;\r
+               \r
                /// <summary>\r
                /// インストールするパッケージ\r
                /// </summary>\r
-               public Package InstalledPackage;\r
+               public Package InstalledPackage {\r
+                       get { return installedPackage; }\r
+                       set {\r
+                               installedPackage = value;\r
+                               \r
+                               installerFile = getArchiveFilePath();\r
+                               installerIndex = GetPreferInstallerIndex(value);\r
+                       }\r
+               }\r
 \r
                /// <summary>\r
                /// (保存される)インストーラのファイルのパス\r
                /// </summary>\r
-               public string InstallerFile;\r
+               private string installerFile;\r
 \r
                /// <summary>\r
                /// インストールが完了されたか否かのフラグ\r
@@ -50,27 +61,30 @@ namespace NaGet.Packages.Install
                /// <summary>\r
                /// コンストラクタ\r
                /// </summary>\r
-               /// <param name="package">インストールするパッケージ</param>\r
-               public Installation(Package package)\r
+               public Installation()\r
                {\r
-                       InstalledPackage = package;\r
-                       InstallerFile = getArchiveFilePath();\r
-                       installerIndex = GetPreferInstallerIndex(package);\r
                }\r
                \r
                /// <summary>\r
                /// コンストラクタ\r
                /// </summary>\r
                /// <param name="package">インストールするパッケージ</param>\r
-               /// <param name="installerfile">(保存される)インストーラのファイルのパス</param>\r
-               protected Installation(Package package, string installerfile)\r
+               public Installation(Package package)\r
                {\r
                        InstalledPackage = package;\r
-                       InstallerFile = installerfile;\r
-                       installerIndex = GetPreferInstallerIndex(package);\r
                }\r
                \r
                /// <summary>\r
+               /// インストーラファイルを取得する\r
+               /// </summary>\r
+               public string InstallerFile {\r
+                       get { return installerFile; }\r
+               }\r
+               \r
+               \r
+               #region インストーラ状態チェック関連\r
+               \r
+               /// <summary>\r
                /// インストール可能か否か\r
                /// </summary>\r
                public bool IsInstallablePackage()\r
@@ -83,7 +97,7 @@ namespace NaGet.Packages.Install
                /// </summary>\r
                public bool Downloaded {\r
                        get {\r
-                               return File.Exists(InstallerFile) && ((File.GetAttributes(InstallerFile) & FileAttributes.Hidden) != FileAttributes.Hidden);\r
+                               return File.Exists(installerFile) && ((File.GetAttributes(installerFile) & FileAttributes.Hidden) != FileAttributes.Hidden);\r
                        }\r
                }\r
                \r
@@ -100,7 +114,10 @@ namespace NaGet.Packages.Install
                public bool InstallSuccessed {\r
                        get {\r
                                switch (InstalledPackage.Type) {\r
-                                       case InstallerType.ARCHIVE: // アーカイブインストーラはフォルダの確認\r
+                                       case InstallerType.ARCHIVE:\r
+                                       case InstallerType.ITSELF:\r
+                                               // アーカイブインストーラおよび配布exeそれ自身が実行ファイルのとき、\r
+                                               // (AppliStationの作る)プログラムフォルダの存在のみで確認を行う。\r
                                                return Directory.Exists(Path.Combine(NaGet.Env.ArchiveProgramFiles, InstalledPackage.Name));\r
                                        case InstallerType.EXEC_INSTALLER:\r
                                        case InstallerType.MSI_PACKAGE:\r
@@ -116,7 +133,7 @@ namespace NaGet.Packages.Install
                /// </summary>\r
                public bool Silent {\r
                        get {\r
-                               return (IsSupportsSilentOnly)? true :\r
+                               return (SupportsSilentOnly)? true :\r
                                        (IsSupportsSilent)? silent :\r
                                        false;\r
                        }\r
@@ -130,8 +147,11 @@ namespace NaGet.Packages.Install
                        get {\r
                                switch (InstalledPackage.Type) {\r
                                        case InstallerType.ARCHIVE:\r
+                                       case InstallerType.ITSELF:\r
                                        case InstallerType.MSI_PACKAGE:\r
                                                return true;\r
+                                       case InstallerType.EXEC_INSTALLER:\r
+                                               return ! string.IsNullOrEmpty(InstalledPackage.SilentInstallArguments);\r
                                        default:\r
                                                return false;\r
                                }\r
@@ -141,11 +161,27 @@ namespace NaGet.Packages.Install
                /// <summary>\r
                /// サイレントインストールだけをサポートしているか否か\r
                /// </summary>\r
-               public bool IsSupportsSilentOnly {\r
-                       get { return InstalledPackage.Type == InstallerType.ARCHIVE; }\r
+               public bool SupportsSilentOnly {\r
+                       get {\r
+                               return (InstalledPackage.Type == InstallerType.ARCHIVE)\r
+                                       || (InstalledPackage.Type == InstallerType.ITSELF);\r
+                       }\r
                }\r
                \r
                /// <summary>\r
+               /// 選択されたパッケージは、AppliStationではなくPCへのインストールをするのか否かを返す。\r
+               /// </summary>\r
+               /// <remark>RunAsが必要か否かの判断にしようされる</remark>\r
+               public bool TargetPC {\r
+                       get {\r
+                               return (InstalledPackage.Type != InstallerType.ARCHIVE)\r
+                                       && (InstalledPackage.Type != InstallerType.ITSELF);\r
+                       }\r
+               }\r
+               \r
+               #endregion\r
+               \r
+               /// <summary>\r
                /// ダウンロードを行う。\r
                /// </summary>\r
                /// <param name="downloader">ダウンローダオブジェクト</param>\r
@@ -153,14 +189,45 @@ namespace NaGet.Packages.Install
                {\r
                        if (! Installed) {\r
                                string url = InstalledPackage.Installer[installerIndex].Url.Href;\r
-                               downloader.Download(url, InstallerFile);\r
+                               downloader.Download(url, installerFile);\r
                                \r
                                // サーバ指定のファイル名に変更する\r
                                if (! string.IsNullOrEmpty(downloader.DownloadedFileName)) {\r
-                                       string newFile = Path.Combine(Path.GetDirectoryName(InstallerFile), downloader.DownloadedFileName);\r
-                                       File.Move(InstallerFile, newFile);\r
-                                       InstallerFile = newFile;\r
+                                       string newFile = Path.Combine(Path.GetDirectoryName(installerFile), downloader.DownloadedFileName);\r
+                                       File.Move(installerFile, newFile);\r
+                                       installerFile = newFile;\r
                                }\r
+                               \r
+                               // 権限を親フォルダに落とす\r
+                               try {\r
+                                       string targetDir = Path.GetDirectoryName(installerFile);\r
+                                       NaGet.Utils.SetAccessControlRecursive(targetDir, File.GetAccessControl(Path.GetDirectoryName(targetDir)));\r
+                               } catch (Exception) {} // 失敗時は何もしない\r
+                       }\r
+               }\r
+               \r
+               /// <summary>\r
+               /// インストーラファイルをスキャンする\r
+               /// </summary>\r
+               /// <remarks>ウイルスのため退避・削除されたときも例外を投げずにあたかも正常かのように動作しえます。</remarks>\r
+               /// <exception cref="ComException">スキャンで意図せぬ動作があったとき</exception>\r
+               /// <exception cref="FileNotFoundException">スキャン後にインストーラファイルが存在しないとき</exception>\r
+               /// <param name="scanner">スキャナーオブジェクト</param>\r
+               public void ScanInstallerFile(DownloadScanner scanner)\r
+               {\r
+                       Exception e = null;\r
+                       try {\r
+                               scanner.Scan(installerFile, InstalledPackage.Installer[installerIndex].Url.Href);\r
+                       } catch (System.Runtime.InteropServices.COMException ex) {\r
+                               e = ex;\r
+                       }\r
+                       \r
+                       if (! File.Exists(installerFile)) {\r
+                               // ファイルが消されているならばFileNotFoundExceptionを出す\r
+                               throw new FileNotFoundException(string.Empty, installerFile, e);\r
+                       } else if ( e != null ) {\r
+                               // ファイルが消されていないが例外が発生していたときは、その例外を投げる\r
+                               throw e;\r
                        }\r
                }\r
                \r
@@ -183,7 +250,7 @@ namespace NaGet.Packages.Install
                        HashValue[] hashValues = InstalledPackage.Installer[installerIndex].Hash;\r
                        if (hashValues != null) {\r
                                foreach (HashValue hash in hashValues) {\r
-                                       if (! hash.Validate(InstallerFile)) {\r
+                                       if (! hash.Validate(installerFile)) {\r
                                                return false;\r
                                        }\r
                                }\r
@@ -202,25 +269,38 @@ namespace NaGet.Packages.Install
                        try {\r
                                switch (type) {\r
                                case InstallerType.EXEC_INSTALLER:\r
-                                       hProcess = Process.Start(installerfile);\r
+                                       if (Silent) {\r
+                                               hProcess = Process.Start(installerfile, InstalledPackage.SilentInstallArguments);\r
+                                       } else {\r
+                                               hProcess = Process.Start(installerfile);\r
+                                       }\r
                                        \r
                                        break;\r
                                case InstallerType.MSI_PACKAGE:\r
-                                       string msiexecArgs = string.Format("{0} /i \"{1}\"",\r
+                                       string msiexecArgs = string.Format("{0} /norestart /i \"{1}\" REBOOT=ReallySuppress",\r
                                                                    (Silent)? "/passive" : string.Empty,\r
                                                                    installerfile);\r
                                        \r
                                        hProcess = Process.Start("msiexec", msiexecArgs);\r
                                        break;\r
                                case InstallerType.ARCHIVE:\r
+                               case InstallerType.ITSELF:\r
                                        string argument = string.Format("-i \"{0}\" \"{1}\"", installerfile, this.InstalledPackage.Name);\r
                                        hProcess = createExtractArchiveProcess(argument,\r
                                                                               this.OutputDataReceived,\r
                                                                               this.ErrorDataReceived);\r
+                                       // Note: ARCHIVEかITSELFの判断はarchive-instが行う\r
                                        break;\r
                                default:\r
                                        throw new NotImplementedException("Not implemented archive installation yet");\r
                                }\r
+                               \r
+                               if (NaGet.Env.InstallProcessOnBackground) {\r
+                                       try {\r
+                                               hProcess.PriorityClass = ProcessPriorityClass.Idle;\r
+                                       } catch (Exception) {}\r
+                               }\r
+                               \r
                                hProcess.WaitForExit();\r
                                \r
                                return hProcess.ExitCode;\r
@@ -237,7 +317,7 @@ namespace NaGet.Packages.Install
                /// <returns>インストーラの終了コード</returns>\r
                public int Install()\r
                {\r
-                       string installerFile = this.InstallerFile;\r
+                       string installerFile = this.installerFile;\r
                        string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());\r
                        \r
                        // アーカイブされているなら一旦展開\r
@@ -248,6 +328,12 @@ namespace NaGet.Packages.Install
                                using (Process hProcess = createExtractArchiveProcess(argument,\r
                                                                                      this.OutputDataReceived,\r
                                                                                      this.ErrorDataReceived)) {\r
+                                       if (NaGet.Env.InstallProcessOnBackground) {\r
+                                               try {\r
+                                                       hProcess.PriorityClass = ProcessPriorityClass.Idle;\r
+                                               } catch (Exception) {}\r
+                                       }\r
+                                       \r
                                        hProcess.WaitForExit();\r
                                \r
                                        if (hProcess.ExitCode != 0) {\r
@@ -261,7 +347,6 @@ namespace NaGet.Packages.Install
                                }\r
                        }\r
                        \r
-                       \r
                        int exitCode = invokeInstaller(installerFile, InstalledPackage.Type);\r
                        \r
                        installed = true;\r
@@ -302,7 +387,7 @@ namespace NaGet.Packages.Install
                }\r
                \r
                /// <summary>\r
-               /// ã\82¤ã\83³ã\82¹ã\83\88ã\83¼ã\83©ã\81®ä¸\80æ\99\82ä¿\9då­\98å\85\88ã\83\91ã\82¹ã\82\92ç\94\9fæ\88\90\r
+               /// インストーラの保存先パスを生成\r
                /// </summary>\r
                private string getArchiveFilePath()\r
                {\r
@@ -320,6 +405,11 @@ namespace NaGet.Packages.Install
                                        }\r
                                } else {\r
                                        Directory.CreateDirectory(folder);\r
+                                       \r
+                                       // 権限を親フォルダに合わせる\r
+                                       try {\r
+                                               Directory.SetAccessControl(folder, Directory.GetAccessControl(Path.GetDirectoryName(folder)));\r
+                                       } catch (Exception) {} // 失敗時無視\r
                                }\r
                        }\r
                        \r
@@ -367,6 +457,9 @@ namespace NaGet.Packages.Install
                                        list.AddRange(Directory.GetFiles(basedir, "*.7z"));\r
                                        list.AddRange(Directory.GetFiles(basedir, "*.tar*"));\r
                                        break;\r
+                               case InstallerType.ITSELF:\r
+                                       list.AddRange(Directory.GetFiles(basedir, "*.exe"));\r
+                                       break;\r
                                default:\r
                                        return null;\r
                        }\r
@@ -408,6 +501,8 @@ namespace NaGet.Packages.Install
                                                               new FileNotFoundException(errMsg, archiveInstExe));\r
                        }\r
                        \r
+                       \r
+                       \r
                        ProcessStartInfo procInfo = new ProcessStartInfo(archiveInstExe, archiveInstArgs);\r
                        procInfo.UseShellExecute = false;\r
                        procInfo.CreateNoWindow = true;\r
@@ -416,6 +511,16 @@ namespace NaGet.Packages.Install
                        return NaGet.Utils.ProcessStartWithOutputCapture(procInfo, outputReceived, errorReceived);\r
                }\r
                \r
+               /// <summary>\r
+               /// ダウンロードしたインストーラファイルを削除する\r
+               /// </summary>\r
+               public virtual void RemoveDownloadedFile()\r
+               {\r
+                       if (Downloaded && File.Exists(installerFile)) {\r
+                               File.Delete(installerFile);\r
+                       }\r
+               }\r
+               \r
                public override string ToString()\r
                {\r
                        return string.Format("{0}({1})", InstalledPackage.Name, InstalledPackage.Version);\r