From 69f097cac9710d253c591debc1c6d0c742a5660d Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Thu, 11 Oct 2018 22:21:34 -0500 Subject: [PATCH] Updating now extracts to a 'Pending' directory and installs on the next game start --- IPA.Injector/IPA.Injector.csproj | 1 + IPA.Injector/Injector.cs | 11 +--- IPA.Injector/Updates.cs | 57 +++++++++++++++++++ IPA.Loader/Updating/ModsaberML/Updater.cs | 66 ++++++++++++++-------- IPA.Loader/Utilities/BeatSaber.cs | 6 +- IPA.Loader/Utilities/LoneFunctions.cs | 37 ++++++++++++ Refs/UnityEngine.CoreModule.dll | Bin 539136 -> 539136 bytes 7 files changed, 144 insertions(+), 34 deletions(-) create mode 100644 IPA.Injector/Updates.cs diff --git a/IPA.Injector/IPA.Injector.csproj b/IPA.Injector/IPA.Injector.csproj index 83e9ebdd..44034094 100644 --- a/IPA.Injector/IPA.Injector.csproj +++ b/IPA.Injector/IPA.Injector.csproj @@ -59,6 +59,7 @@ + diff --git a/IPA.Injector/Injector.cs b/IPA.Injector/Injector.cs index a0feae57..f96b602a 100644 --- a/IPA.Injector/Injector.cs +++ b/IPA.Injector/Injector.cs @@ -11,7 +11,6 @@ using System.Reflection; using System.Runtime.InteropServices; using UnityEngine; using static IPA.Logging.Logger; -using Logger = IPA.Logging.Logger; using MethodAttributes = Mono.Cecil.MethodAttributes; namespace IPA.Injector @@ -27,19 +26,15 @@ namespace IPA.Injector try { - // This loads System.Runtime.InteropServices, and Microsoft.Win32.SafeHandles. Windows.WinConsole.Initialize(); - // This loads AppDomain, System.IO, System.Collections.Generic, and System.Reflection. - // If kernel32.dll is not already loaded, this will also load it. - // This call also loads IPA.Loader and initializes the logging system. In the process - // it loads Ionic.Zip. SetupLibraryLoading(); loader.Debug("Prepping bootstrapper"); - - // // This will load Mono.Cecil + InstallBootstrapPatch(); + + Updates.InstallPendingUpdates(); } catch (Exception e) { diff --git a/IPA.Injector/Updates.cs b/IPA.Injector/Updates.cs new file mode 100644 index 00000000..658483b8 --- /dev/null +++ b/IPA.Injector/Updates.cs @@ -0,0 +1,57 @@ +using IPA.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static IPA.Logging.Logger; + +namespace IPA.Injector +{ + class Updates + { + public const string DeleteFileName = Updating.ModsaberML.Updater._SpecialDeletionsFile; + public static void InstallPendingUpdates() + { + var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); + if (Directory.Exists(pendingDir)) + { // there are pending updates, install + updater.Info("Installing pending updates"); + + var toDelete = new string[0]; + var delFn = Path.Combine(pendingDir, DeleteFileName); + if (File.Exists(delFn)) + { + toDelete = File.ReadAllLines(delFn); + File.Delete(delFn); + } + + foreach (var file in toDelete) + { + try + { + File.Delete(Path.Combine(BeatSaber.InstallPath, file)); + } + catch (Exception e) + { + updater.Error("While trying to install pending updates: Error deleting file marked for deletion"); + updater.Error(e); + } + } + + try + { + LoneFunctions.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(BeatSaber.InstallPath)); + } + catch (Exception e) + { + updater.Error("While trying to install pending updates: Error copying files in"); + updater.Error(e); + } + + Directory.Delete(pendingDir, true); + } + } + } +} diff --git a/IPA.Loader/Updating/ModsaberML/Updater.cs b/IPA.Loader/Updating/ModsaberML/Updater.cs index a1ae5500..0ab9c9d3 100644 --- a/IPA.Loader/Updating/ModsaberML/Updater.cs +++ b/IPA.Loader/Updating/ModsaberML/Updater.cs @@ -286,7 +286,10 @@ namespace IPA.Updating.ModsaberML continue; } - var ver = modsMatching.Value.Where(val => val.GameVersion == BeatSaber.GameVersion && val.Approved && !dep.Conflicts.IsSatisfied(val.Version)).Select(mod => mod.Version).Max(); // (2.1) + var ver = modsMatching.Value.Where(nullCheck => nullCheck != null) + .Where(versionCheck => versionCheck.GameVersion == BeatSaber.GameVersion && versionCheck.Approved) + .Where(conflictsCheck => dep.Conflicts == null || !dep.Conflicts.IsSatisfied(conflictsCheck.Version)) + .Select(mod => mod.Version).Max(); // (2.1) if (dep.Resolved = ver != null) dep.ResolvedVersion = ver; // (2.2) dep.Has = dep.Version == dep.ResolvedVersion && dep.Resolved; // dep.Version is only not null if its already installed } @@ -470,11 +473,17 @@ namespace IPA.Updating.ModsaberML throw new Exception("The hash for the file doesn't match what is defined"); var newFiles = new List(); - var backup = new BackupUnit(tempDirectory, $"backup-{item.Name}"); + + var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending"); + Directory.CreateDirectory(targetDir); + + var eventualOutput = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); + if (!Directory.Exists(eventualOutput)) + Directory.CreateDirectory(eventualOutput); try { - bool shouldDeleteOldFile = true; + bool shouldDeleteOldFile = !(item.LocalPluginMeta?.Plugin is SelfPlugin); using (var zipFile = ZipFile.Read(stream)) { @@ -484,7 +493,7 @@ namespace IPA.Updating.ModsaberML if (entry.IsDirectory) { Logger.updater.Debug($"Creating directory {entry.FileName}"); - Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, entry.FileName)); + Directory.CreateDirectory(Path.Combine(targetDir, entry.FileName)); } else { @@ -507,53 +516,60 @@ namespace IPA.Updating.ModsaberML } ostream.Seek(0, SeekOrigin.Begin); - FileInfo targetFile = new FileInfo(Path.Combine(Environment.CurrentDirectory, entry.FileName)); + FileInfo targetFile = new FileInfo(Path.Combine(targetDir, entry.FileName)); Directory.CreateDirectory(targetFile.DirectoryName); - if (targetFile.FullName == item.LocalPluginMeta?.Filename) + if (LoneFunctions.GetRelativePath(targetFile.FullName, targetDir) == LoneFunctions.GetRelativePath(item.LocalPluginMeta?.Filename, BeatSaber.InstallPath)) shouldDeleteOldFile = false; // overwriting old file, no need to delete - if (targetFile.Exists) + /*if (targetFile.Exists) backup.Add(targetFile); else - newFiles.Add(targetFile); + newFiles.Add(targetFile);*/ Logger.updater.Debug($"Extracting file {targetFile.FullName}"); targetFile.Delete(); - var fstream = targetFile.Create(); - ostream.CopyTo(fstream); + using (var fstream = targetFile.Create()) + ostream.CopyTo(fstream); } } } } - - if (item.LocalPluginMeta?.Plugin is SelfPlugin) - { // currently updating self - Process.Start(new ProcessStartInfo - { - FileName = item.LocalPluginMeta.Filename, - Arguments = $"-nw={Process.GetCurrentProcess().Id}", - UseShellExecute = false - }); - } - else if (shouldDeleteOldFile && item.LocalPluginMeta != null) - File.Delete(item.LocalPluginMeta.Filename); + + if (shouldDeleteOldFile && item.LocalPluginMeta != null) + File.AppendAllLines(Path.Combine(targetDir, _SpecialDeletionsFile), new string[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) }); } catch (Exception) { // something failed; restore - foreach (var file in newFiles) + /*foreach (var file in newFiles) file.Delete(); backup.Restore(); - backup.Delete(); + backup.Delete();*/ + Directory.Delete(targetDir, true); // delete extraction site throw; } - backup.Delete(); + if (item.LocalPluginMeta?.Plugin is SelfPlugin) + { // currently updating self, so copy to working dir and update + LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(BeatSaber.InstallPath)); + if (File.Exists(Path.Combine(BeatSaber.InstallPath, _SpecialDeletionsFile))) File.Delete(Path.Combine(BeatSaber.InstallPath, _SpecialDeletionsFile)); + Process.Start(new ProcessStartInfo + { + FileName = item.LocalPluginMeta.Filename, + Arguments = $"-nw={Process.GetCurrentProcess().Id}", + UseShellExecute = false + }); + } + else + LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), _SpecialDeletionsFile); + Directory.Delete(targetDir, true); // delete extraction site Logger.updater.Debug("Extractor exited"); } + + internal const string _SpecialDeletionsFile = "$$delete"; } [Serializable] diff --git a/IPA.Loader/Utilities/BeatSaber.cs b/IPA.Loader/Utilities/BeatSaber.cs index f93ce0e6..e7f6ec28 100644 --- a/IPA.Loader/Utilities/BeatSaber.cs +++ b/IPA.Loader/Utilities/BeatSaber.cs @@ -40,10 +40,14 @@ namespace IPA.Utilities /// public static Release ReleaseType => (_releaseCache ?? (_releaseCache = FindSteamVRAsset() ? Release.Steam : Release.Oculus)).Value; + /// + /// The path to the Beat Saber install dir + /// + public static string InstallPath => Environment.CurrentDirectory; /// /// The path to the `Libs` folder. Use only if necessary. /// - public static string LibraryPath => Path.Combine(Environment.CurrentDirectory, "Libs"); + public static string LibraryPath => Path.Combine(InstallPath, "Libs"); /// /// The path to the `Libs\Native` folder. Use only if necessary. /// diff --git a/IPA.Loader/Utilities/LoneFunctions.cs b/IPA.Loader/Utilities/LoneFunctions.cs index 15dc9263..eb44920c 100644 --- a/IPA.Loader/Utilities/LoneFunctions.cs +++ b/IPA.Loader/Utilities/LoneFunctions.cs @@ -84,5 +84,42 @@ namespace IPA.Utilities Uri folderUri = new Uri(folder); return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar)); } + + /// + /// Copies all files from to . + /// + /// the source directory + /// the destination directory + /// + public static void CopyAll(DirectoryInfo source, DirectoryInfo target, string appendFileName = "") + { + if (source.FullName.ToLower() == target.FullName.ToLower()) + { + return; + } + + // Check if the target directory exists, if not, create it. + if (Directory.Exists(target.FullName) == false) + { + Directory.CreateDirectory(target.FullName); + } + + // Copy each file into it's new directory. + foreach (FileInfo fi in source.GetFiles()) + { + if (fi.Name == appendFileName) + File.AppendAllLines(Path.Combine(target.ToString(), fi.Name), File.ReadAllLines(fi.FullName)); + else + fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true); + } + + // Copy each subdirectory using recursion. + foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) + { + DirectoryInfo nextTargetSubDir = + target.CreateSubdirectory(diSourceSubDir.Name); + CopyAll(diSourceSubDir, nextTargetSubDir, appendFileName); + } + } } } diff --git a/Refs/UnityEngine.CoreModule.dll b/Refs/UnityEngine.CoreModule.dll index 06b84914cbbe08d5cad3c6a095d83874b683fade..1ef24630788099fcae157ea60b585cff5d1a0927 100644 GIT binary patch delta 40 vcmZqpqR{X~VL}J9Gyj3c?$&O`)^4WOZsyi*mey|8)^4`eZuYI+9Ho{3TcQu- delta 40 wcmZqpqR{X~VL}J%Tf3QByO~?NSz5bUTf5m>yV