summaryrefslogtreecommitdiff
path: root/src/SMAPI.Mods.SaveBackup
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2019-11-24 13:49:30 -0500
commita3f21685049cabf2d824c8060dc0b1de47e9449e (patch)
treead9add30e9da2a50e0ea0245f1546b7378f0d282 /src/SMAPI.Mods.SaveBackup
parent6521df7b131924835eb797251c1e956fae0d6e13 (diff)
parent277bf082675b98b95bf6184fe3c7a45b969c7ac2 (diff)
downloadSMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.gz
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.tar.bz2
SMAPI-a3f21685049cabf2d824c8060dc0b1de47e9449e.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI.Mods.SaveBackup')
-rw-r--r--src/SMAPI.Mods.SaveBackup/ModEntry.cs142
-rw-r--r--src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs4
-rw-r--r--src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj (renamed from src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj)12
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
4 files changed, 102 insertions, 60 deletions
diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
index 30dbfbe6..3b47759b 100644
--- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs
+++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using StardewValley;
namespace StardewModdingAPI.Mods.SaveBackup
@@ -40,9 +41,10 @@ namespace StardewModdingAPI.Mods.SaveBackup
DirectoryInfo backupFolder = new DirectoryInfo(this.BackupFolder);
backupFolder.Create();
- // back up saves
- this.CreateBackup(backupFolder);
- this.PruneBackups(backupFolder, this.BackupsToKeep);
+ // back up & prune saves
+ Task
+ .Run(() => this.CreateBackup(backupFolder))
+ .ContinueWith(backupTask => this.PruneBackups(backupFolder, this.BackupsToKeep));
}
catch (Exception ex)
{
@@ -66,48 +68,23 @@ 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.
- this.Monitor.Log($"Adding {targetFile.Name}...", LogLevel.Trace);
- switch (Constants.TargetPlatform)
+ // back up saves
+ this.Monitor.Log($"Backing up saves to {targetFile.FullName}...", LogLevel.Trace);
+ if (!this.TryCompress(Constants.SavesPath, targetFile, out Exception compressError))
{
- 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);
}
catch (Exception ex)
{
@@ -124,20 +101,23 @@ namespace StardewModdingAPI.Mods.SaveBackup
try
{
var oldBackups = backupFolder
- .GetFiles()
+ .GetFileSystemInfos()
.OrderByDescending(p => p.CreationTimeUtc)
.Skip(backupsToKeep);
- foreach (FileInfo file in oldBackups)
+ foreach (FileSystemInfo entry in oldBackups)
{
try
{
- this.Monitor.Log($"Deleting {file.Name}...", LogLevel.Trace);
- file.Delete();
+ this.Monitor.Log($"Deleting {entry.Name}...", LogLevel.Trace);
+ if (entry is DirectoryInfo folder)
+ folder.Delete(recursive: true);
+ else
+ entry.Delete();
}
catch (Exception ex)
{
- this.Monitor.Log($"Error deleting old save backup '{file.Name}': {ex}", LogLevel.Error);
+ this.Monitor.Log($"Error deleting old save backup '{entry.Name}': {ex}", LogLevel.Error);
}
}
}
@@ -148,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>
diff --git a/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs b/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs
deleted file mode 100644
index fc6b26fa..00000000
--- a/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-using System.Reflection;
-
-[assembly: AssemblyTitle("StardewModdingAPI.Mods.SaveBackup")]
-[assembly: AssemblyDescription("")]
diff --git a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj
index 460f3c93..2d031408 100644
--- a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj
+++ b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj
@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <RootNamespace>StardewModdingAPI.Mods.SaveBackup</RootNamespace>
<AssemblyName>SaveBackup</AssemblyName>
+ <RootNamespace>StardewModdingAPI.Mods.SaveBackup</RootNamespace>
<TargetFramework>net45</TargetFramework>
- <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>latest</LangVersion>
<OutputPath>$(SolutionDir)\..\bin\$(Configuration)\Mods\SaveBackup</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -12,15 +11,16 @@
</PropertyGroup>
<ItemGroup>
- <ProjectReference Include="..\SMAPI\StardewModdingAPI.csproj">
+ <ProjectReference Include="..\SMAPI\SMAPI.csproj">
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <Compile Include="..\..\build\GlobalAssemblyInfo.cs">
- <Link>Properties\GlobalAssemblyInfo.cs</Link>
- </Compile>
+ <Reference Include="$(GameExecutableName)">
+ <HintPath>$(GamePath)\$(GameExecutableName).exe</HintPath>
+ <Private>False</Private>
+ </Reference>
</ItemGroup>
<ItemGroup>
diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json
index e147bd39..eddd3443 100644
--- a/src/SMAPI.Mods.SaveBackup/manifest.json
+++ b/src/SMAPI.Mods.SaveBackup/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
- "Version": "2.11.3",
+ "Version": "3.0.0",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
- "MinimumApiVersion": "2.11.3"
+ "MinimumApiVersion": "3.0.0"
}