summaryrefslogtreecommitdiff
path: root/src/SMAPI.Mods.SaveBackup
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-10-07 15:05:01 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-10-07 15:05:01 -0400
commitb4a8c1c2ac9d1b3796a144d267cceadf5f7831ff (patch)
treeecbad9846dc0d5f4bef469cd676052a554a43669 /src/SMAPI.Mods.SaveBackup
parent175ebf907134e1e32992f62637a5d7e43bfc6a20 (diff)
downloadSMAPI-b4a8c1c2ac9d1b3796a144d267cceadf5f7831ff.tar.gz
SMAPI-b4a8c1c2ac9d1b3796a144d267cceadf5f7831ff.tar.bz2
SMAPI-b4a8c1c2ac9d1b3796a144d267cceadf5f7831ff.zip
rework Save Backup to support Android
Diffstat (limited to 'src/SMAPI.Mods.SaveBackup')
-rw-r--r--src/SMAPI.Mods.SaveBackup/ModEntry.cs119
1 files changed, 79 insertions, 40 deletions
diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
index efc6f39f..3b47759b 100644
--- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs
+++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
@@ -68,48 +68,21 @@ namespace StardewModdingAPI.Mods.SaveBackup
if (targetFile.Exists || fallbackDir.Exists)
return;
- // create zip
- // due to limitations with the bundled Mono on Mac, we can't reference System.IO.Compression.
+ // back up saves
this.Monitor.Log($"Backing up saves to {targetFile.FullName}...", LogLevel.Trace);
- switch (Constants.TargetPlatform)
+ if (!this.TryCompress(Constants.SavesPath, targetFile, out Exception compressError))
{
- case GamePlatform.Android:
- case GamePlatform.Linux:
- case GamePlatform.Windows:
- {
- try
- {
- // create compressed backup
- Assembly coreAssembly = Assembly.Load("System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
- Assembly fsAssembly = Assembly.Load("System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
- Type compressionLevelType = coreAssembly.GetType("System.IO.Compression.CompressionLevel") ?? throw new InvalidOperationException("Can't load CompressionLevel type.");
- Type zipFileType = fsAssembly.GetType("System.IO.Compression.ZipFile") ?? throw new InvalidOperationException("Can't load ZipFile type.");
- MethodInfo createMethod = zipFileType.GetMethod("CreateFromDirectory", new[] { typeof(string), typeof(string), compressionLevelType, typeof(bool) }) ?? throw new InvalidOperationException("Can't load ZipFile.CreateFromDirectory method.");
- createMethod.Invoke(null, new object[] { Constants.SavesPath, targetFile.FullName, CompressionLevel.Fastest, false });
- }
- catch (Exception ex) when (ex is TypeLoadException || ex.InnerException is TypeLoadException)
- {
- // create uncompressed backup if compression fails
- this.Monitor.Log("Couldn't zip the save backup, creating uncompressed backup instead.", LogLevel.Debug);
- this.Monitor.Log(ex.ToString(), LogLevel.Trace);
- this.RecursiveCopy(new DirectoryInfo(Constants.SavesPath), fallbackDir, copyRoot: false);
- }
- }
- break;
-
- case GamePlatform.Mac:
- {
- DirectoryInfo saveFolder = new DirectoryInfo(Constants.SavesPath);
- ProcessStartInfo startInfo = new ProcessStartInfo
- {
- FileName = "zip",
- Arguments = $"-rq \"{targetFile.FullName}\" \"{saveFolder.Name}\" -x \"*.DS_Store\" -x \"__MACOSX\"",
- WorkingDirectory = $"{Constants.SavesPath}/../",
- CreateNoWindow = true
- };
- new Process { StartInfo = startInfo }.Start();
- }
- break;
+ // log error (expected on Android due to missing compression DLLs)
+ if (Constants.TargetPlatform == GamePlatform.Android)
+ this.Monitor.VerboseLog($"Compression isn't supported on Android:\n{compressError}");
+ else
+ {
+ this.Monitor.Log("Couldn't zip the save backup, creating uncompressed backup instead.", LogLevel.Debug);
+ this.Monitor.Log(compressError.ToString(), LogLevel.Trace);
+ }
+
+ // fallback to uncompressed
+ this.RecursiveCopy(new DirectoryInfo(Constants.SavesPath), fallbackDir, copyRoot: false);
}
this.Monitor.Log("Backup done!", LogLevel.Trace);
}
@@ -155,6 +128,72 @@ namespace StardewModdingAPI.Mods.SaveBackup
}
}
+ /// <summary>Create a zip using the best available method.</summary>
+ /// <param name="sourcePath">The file or directory path to zip.</param>
+ /// <param name="destination">The destination file to create.</param>
+ /// <param name="error">The error which occurred trying to compress, if applicable. This is <see cref="NotSupportedException"/> if compression isn't supported on this platform.</param>
+ /// <returns>Returns whether compression succeeded.</returns>
+ private bool TryCompress(string sourcePath, FileInfo destination, out Exception error)
+ {
+ try
+ {
+ if (Constants.TargetPlatform == GamePlatform.Mac)
+ this.CompressUsingMacProcess(sourcePath, destination); // due to limitations with the bundled Mono on Mac, we can't reference System.IO.Compression
+ else
+ this.CompressUsingNetFramework(sourcePath, destination);
+
+ error = null;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ error = ex;
+ return false;
+ }
+ }
+
+ /// <summary>Create a zip using the .NET compression library.</summary>
+ /// <param name="sourcePath">The file or directory path to zip.</param>
+ /// <param name="destination">The destination file to create.</param>
+ /// <exception cref="NotSupportedException">The compression libraries aren't available on this system.</exception>
+ private void CompressUsingNetFramework(string sourcePath, FileInfo destination)
+ {
+ // get compress method
+ MethodInfo createFromDirectory;
+ try
+ {
+ // create compressed backup
+ Assembly coreAssembly = Assembly.Load("System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
+ Assembly fsAssembly = Assembly.Load("System.IO.Compression.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") ?? throw new InvalidOperationException("Can't load System.IO.Compression assembly.");
+ Type compressionLevelType = coreAssembly.GetType("System.IO.Compression.CompressionLevel") ?? throw new InvalidOperationException("Can't load CompressionLevel type.");
+ Type zipFileType = fsAssembly.GetType("System.IO.Compression.ZipFile") ?? throw new InvalidOperationException("Can't load ZipFile type.");
+ createFromDirectory = zipFileType.GetMethod("CreateFromDirectory", new[] { typeof(string), typeof(string), compressionLevelType, typeof(bool) }) ?? throw new InvalidOperationException("Can't load ZipFile.CreateFromDirectory method.");
+ }
+ catch (Exception ex)
+ {
+ throw new NotSupportedException("Couldn't load the .NET compression libraries on this system.", ex);
+ }
+
+ // compress file
+ createFromDirectory.Invoke(null, new object[] { sourcePath, destination.FullName, CompressionLevel.Fastest, false });
+ }
+
+ /// <summary>Create a zip using a process command on MacOS.</summary>
+ /// <param name="sourcePath">The file or directory path to zip.</param>
+ /// <param name="destination">The destination file to create.</param>
+ private void CompressUsingMacProcess(string sourcePath, FileInfo destination)
+ {
+ DirectoryInfo saveFolder = new DirectoryInfo(sourcePath);
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = "zip",
+ Arguments = $"-rq \"{destination.FullName}\" \"{saveFolder.Name}\" -x \"*.DS_Store\" -x \"__MACOSX\"",
+ WorkingDirectory = $"{saveFolder.FullName}/../",
+ CreateNoWindow = true
+ };
+ new Process { StartInfo = startInfo }.Start();
+ }
+
/// <summary>Recursively copy a directory or file.</summary>
/// <param name="source">The file or folder to copy.</param>
/// <param name="targetFolder">The folder to copy into.</param>