You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.5 KiB

  1. using IPA.Logging;
  2. using IPA.Utilities;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.Specialized;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. namespace IPA.Updating.Backup
  10. {
  11. /// <summary>
  12. /// A unit for backup. WIP.
  13. /// </summary>
  14. internal class BackupUnit
  15. {
  16. public string Name { get; private set; }
  17. private DirectoryInfo _BackupPath;
  18. private List<string> _Files = new List<string>();
  19. private FileInfo _ManifestFile;
  20. private static string _ManifestFileName = "$manifest$.txt";
  21. public BackupUnit(string path) : this(path, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss"))
  22. {
  23. }
  24. internal BackupUnit(string path, string name)
  25. {
  26. Name = name;
  27. _BackupPath = new DirectoryInfo(Path.Combine(path, Name));
  28. _ManifestFile = new FileInfo(Path.Combine(_BackupPath.FullName, _ManifestFileName));
  29. }
  30. public static BackupUnit FromDirectory(DirectoryInfo directory, string backupPath)
  31. {
  32. var unit = new BackupUnit(backupPath, directory.Name);
  33. // Read Manifest
  34. if (unit._ManifestFile.Exists)
  35. {
  36. string manifest = File.ReadAllText(unit._ManifestFile.FullName);
  37. foreach (var line in manifest.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
  38. unit._Files.Add(line);
  39. }
  40. else
  41. {
  42. foreach (var file in directory.GetFiles("*", SearchOption.AllDirectories))
  43. {
  44. if (file.Name == _ManifestFileName) continue;
  45. var relativePath = file.FullName.Substring(directory.FullName.Length + 1);
  46. unit._Files.Add(relativePath);
  47. }
  48. }
  49. return unit;
  50. }
  51. public void Add(string file)
  52. {
  53. Add(new FileInfo(file));
  54. }
  55. internal void Delete()
  56. {
  57. _BackupPath.Delete(true);
  58. }
  59. /// <summary>
  60. /// Adds a file to the list of changed files and backups it.
  61. /// </summary>
  62. /// <param name="file"></param>
  63. public void Add(FileInfo file)
  64. {
  65. var relativePath = LoneFunctions.GetRelativePath(Environment.CurrentDirectory, file.FullName);
  66. var backupPath = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath));
  67. if (_Files.Contains(relativePath))
  68. {
  69. Logger.updater.Debug($"Skipping backup of {relativePath}");
  70. return;
  71. }
  72. // Copy over
  73. backupPath.Directory.Create();
  74. if (file.Exists)
  75. {
  76. file.CopyTo(backupPath.FullName);
  77. }
  78. else
  79. {
  80. // Make empty file
  81. backupPath.Create().Close();
  82. }
  83. if (!File.Exists(_ManifestFile.FullName))
  84. _ManifestFile.Create().Close();
  85. var stream = _ManifestFile.AppendText();
  86. stream.WriteLine(relativePath);
  87. stream.Close();
  88. // Add to list
  89. _Files.Add(relativePath);
  90. }
  91. /// <summary>
  92. /// Reverts the changes made in this unit.
  93. /// </summary>
  94. public void Restore()
  95. {
  96. foreach (var relativePath in _Files)
  97. {
  98. Logger.updater.Debug($"Restoring {relativePath}");
  99. // Original version
  100. var backupFile = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath));
  101. var target = new FileInfo(Path.Combine(Environment.CurrentDirectory, relativePath));
  102. if (backupFile.Exists)
  103. {
  104. if (backupFile.Length > 0)
  105. {
  106. Logger.updater.Debug($" {backupFile.FullName} => {target.FullName}");
  107. target.Directory.Create();
  108. backupFile.CopyTo(target.FullName, true);
  109. }
  110. else
  111. {
  112. Logger.updater.Debug($" x {target.FullName}");
  113. if (target.Exists)
  114. {
  115. target.Delete();
  116. }
  117. }
  118. }
  119. else
  120. {
  121. Logger.updater.Error("Backup not found!");
  122. }
  123. }
  124. }
  125. }
  126. }