/// <summary> /// Store a <see cref="UpdateReport" /> in a <see cref="ZipFile" />. /// </summary> /// <param name="zip"><see cref="ZipFile" /> to write to.</param> /// <param name="report"><see cref="UpdateReport" /> to store.</param> private static void StoreReport(ZipFile zip, UpdateReport report) { var textTarget = string.Format(UpdateReportTextFile, report.PreviousVersion, report.UpdateVersion); zip.UpdateEntry(textTarget, string.Join(Environment.NewLine, report.Changes.Select(_ => _.ToString())), ZipEncoding); var yamlTarget = string.Format(UpdateReportYamlFile, report.PreviousVersion, report.UpdateVersion); var serializer = new Serializer(); byte[] yamlBuffer; using (var ms = new MemoryStream()) { using (TextWriter writer = new StreamWriter(ms, ZipEncoding)) { serializer.Serialize(writer, report); writer.Flush(); yamlBuffer = ms.ToArray(); } } zip.UpdateEntry(yamlTarget, yamlBuffer); var binTarget = string.Format(UpdateReportBinFile, report.PreviousVersion, report.UpdateVersion); var formatter = new BinaryFormatter(); byte[] binBuffer; using (var ms = new MemoryStream()) { formatter.Serialize(ms, report); binBuffer = ms.ToArray(); } zip.UpdateEntry(binTarget, binBuffer); }
/// <summary> /// Update to the current version. /// </summary> /// <param name="detectDataChanges">Boolean indicating whether the update should also look for changes in data.</param> /// <param name="progress">Optional object to which update progress is reported.</param> /// <returns>Returns the <see cref="UpdateReport" /> containing all changes.</returns> /// <exception cref="InvalidOperationException">Definition is up-to-date.</exception> public UpdateReport Update(bool detectDataChanges, IProgress <UpdateProgress> progress = null) { if (DefinitionVersion == GameVersion) { throw new InvalidOperationException(); } var previousVersion = DefinitionVersion; var exdPackId = new PackIdentifier("exd", PackIdentifier.DefaultExpansion, 0); var exdPack = Packs.GetPack(exdPackId); var exdOldKeepInMemory = exdPack.KeepInMemory; exdPack.KeepInMemory = true; string tempPath = null; UpdateReport report; try { using (var zip = new ZipFile(StateFile.FullName, ZipEncoding)) { tempPath = ExtractPacks(zip, previousVersion); var previousPack = new PackCollection(Path.Combine(tempPath, previousVersion)); previousPack.GetPack(exdPackId).KeepInMemory = true; var previousDefinition = ReadDefinition(zip); var updater = new RelationUpdater(previousPack, previousDefinition, Packs, GameVersion, progress); var changes = updater.Update(detectDataChanges); report = new UpdateReport(previousVersion, GameVersion, changes); var definition = updater.Updated; StorePacks(zip); StoreDefinition(zip, definition, DefinitionFile); StoreDefinition(zip, definition, string.Format("{0}/{1}", definition.Version, DefinitionFile)); StoreReport(zip, report); zip.Save(); GameData.Definition = definition; GameData.Definition.Compile(); } } finally { if (exdPack != null) { exdPack.KeepInMemory = exdOldKeepInMemory; } if (tempPath != null) { try { Directory.Delete(tempPath, true); } catch { Console.Error.WriteLine("Failed to delete temporary directory {0}.", tempPath); } } } return(report); }
/// <summary> /// Store a <see cref="UpdateReport" /> in a <see cref="ZipFile" />. /// </summary> /// <param name="zip"><see cref="ZipFile" /> to write to.</param> /// <param name="report"><see cref="UpdateReport" /> to store.</param> private static void StoreReport(ZipFile zip, UpdateReport report) { var textTarget = string.Format(UpdateReportTextFile, report.PreviousVersion, report.UpdateVersion); zip.UpdateEntry(textTarget, string.Join(Environment.NewLine, report.Changes.Select(_ => _.ToString())), ZipEncoding); var jsonTarget = string.Format(UpdateReportJsonFile, report.PreviousVersion, report.UpdateVersion); var obj = report.ToJson(); var json = JsonConvert.SerializeObject(obj, Formatting.Indented); zip.UpdateEntry(jsonTarget, json); }
/// <summary> /// Update to the current version. /// </summary> /// <param name="detectDataChanges">Boolean indicating whether the update should also look for changes in data.</param> /// <param name="progress">Optional object to which update progress is reported.</param> /// <returns>Returns the <see cref="UpdateReport" /> containing all changes.</returns> /// <exception cref="InvalidOperationException">Definition is up-to-date.</exception> public UpdateReport Update(bool detectDataChanges, IProgress <UpdateProgress> progress = null) { if (DefinitionVersion == GameVersion) { throw new InvalidOperationException(); } var previousVersion = DefinitionVersion; var exdPackId = new PackIdentifier("exd", PackIdentifier.DefaultExpansion, 0); var exdPack = Packs.GetPack(exdPackId); var exdOldKeepInMemory = exdPack.KeepInMemory; exdPack.KeepInMemory = true; string tempPath = null; UpdateReport report; try { using (var zip = new ZipFile(StateFile.FullName, ZipEncoding)) { tempPath = ExtractPacks(zip, previousVersion); var previousPack = new PackCollection(Path.Combine(tempPath, previousVersion)); previousPack.GetPack(exdPackId).KeepInMemory = true; RelationDefinition previousDefinition; if (previousVersion == _GameData.Definition.Version) { // Override previous definition when current definition version matches. // Definitions may have changed since this was recorded and we want to compare that. previousDefinition = _GameData.Definition; } else { // Otherwise, read the previous definition from the zip. previousDefinition = ReadDefinition(zip, previousVersion); } var updater = new RelationUpdater(previousPack, previousDefinition, Packs, GameVersion, progress); var changes = updater.Update(detectDataChanges); report = new UpdateReport(previousVersion, GameVersion, changes); var definition = updater.Updated; StorePacks(zip); StoreDefinitionInZip(zip, definition); StoreDefinitionOnFilesystem(definition, ""); if (Debugger.IsAttached) { // Little QOL path - when updating with the debugger attached, // also write to the project definitions path so no need to copy // them manually afterward. var projectDefinitionsPath = "../../../SaintCoinach"; if (Directory.Exists(projectDefinitionsPath)) { StoreDefinitionOnFilesystem(definition, projectDefinitionsPath); } } StoreReport(zip, report); UpdateVersion(zip); zip.Save(); GameData.Definition = definition; GameData.Definition.Compile(); } } finally { if (exdPack != null) { exdPack.KeepInMemory = exdOldKeepInMemory; } if (tempPath != null) { try { Directory.Delete(tempPath, true); } catch { Console.Error.WriteLine("Failed to delete temporary directory {0}.", tempPath); } } } return(report); }