191203PX Worked on import/export and backupping. Starts to work but sometimes locks up without CPU load during backup generation.

This commit is contained in:
phantomix 2019-12-03 17:43:02 +01:00
parent 20c32ab7a3
commit 4f9aeb743f
8 changed files with 255 additions and 205 deletions

View File

@ -32,7 +32,7 @@ namespace dezentrale
{
public class Program
{
public static uint VersionNumber { get; private set; } = 0x19120200;
public static uint VersionNumber { get; private set; } = 0x19120300;
public static string VersionString { get; private set; } = $"{VersionNumber:x}";
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
@ -181,14 +181,28 @@ namespace dezentrale
Cronjob.Run();
break;
case eMode.Export:
if (!config.ImportExport.Export(config.DbDirectory, DmDirectory)) return 1;
if (!config.ImportExport.VerifyExport(config.DbDirectory, DmDirectory)) return 1;
break;
{
ExportProcess export = new ExportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
OutputDir = Program.DmDirectory,
};
ConsoleLogger logger = new ConsoleLogger();
System.Threading.Thread t = logger.StartRunProcess(export);
if (t != null) t.Join();
else return 1;
//if (!config.ImportExport.Export(config.DbDirectory, DmDirectory)) return 1;
//if (!config.ImportExport.VerifyExport(config.DbDirectory, DmDirectory)) return 1;
if(logger.DialogResult != DialogResult.OK) return 1;
} break;
case eMode.Import:
{
ImportProcess import = new ImportProcess()
{
MemberImportSettings = Program.config.ImportExport,
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
InputDir = Program.DmDirectory,
};
@ -201,7 +215,8 @@ namespace dezentrale
//if (!config.ImportExport.Import(config.DbDirectory, DmDirectory))
//return 1;
if(logger.DialogResult != DialogResult.OK) return 1;
} break;
} break;
case eMode.BankImport:
if (string.IsNullOrEmpty(csvInput))
{

View File

@ -6,54 +6,76 @@ using dezentrale.model;
namespace dezentrale.core
{
/** \brief Export functionality for the database contents
*/
public class ExportProcess : ImportExportBase
{
public ExportProcess()
{
Caption = "Database export";
Steps = 4;
Steps = 6;
}
protected override bool Run()
{
string tmpFile = Path.Combine(OutputDir, MemberImportSettings.ZipFile);
Console.WriteLine($"Export: Packing {tmpFile}");
LogTarget.StepStarted(0, "Preparing export");
if (ImportExportSettings == null)
{
LogTarget.LogLine("MemberImportExport data class not set.", LogEvent.ELogLevel.Error, "ExportProcess");
return false;
}
if (!Directory.Exists(MemberDir))
if (MemberDir == null)
{
Console.WriteLine($"Cannot find directory '{MemberDir}'");
LogTarget.LogLine("Member directory not set.", LogEvent.ELogLevel.Error, "ExportProcess");
return false;
} else if (!Directory.Exists(MemberDir))
{
LogTarget.LogLine($"Cannot find directory '{MemberDir}'", LogEvent.ELogLevel.Error, "ExportProcess");
return false;
}
if (!Directory.Exists(OutputDir))
if (OutputDir == null)
{
Console.WriteLine($"Cannot find directory '{OutputDir}'");
LogTarget.LogLine("Input directory not set.", LogEvent.ELogLevel.Error, "ExportProcess");
return false;
} else if (!Directory.Exists(OutputDir))
{
LogTarget.LogLine($"Cannot find directory '{OutputDir}'", LogEvent.ELogLevel.Error, "ExportProcess");
return false;
}
//TBD: Check if newer version of database is online
LogTarget.StepStarted(1, $"Fetching commits from remote location");
string outFile = Path.Combine(OutputDir, ImportExportSettings.ZipFile);
try
{
// Depending on the directory this could be very large and would require more attention
// in a commercial package.
string[] filenames = Directory.GetFiles(MemberDir, "*.xml");
string outFile = Path.Combine(OutputDir, MemberImportSettings.ZipFile);
if (File.Exists(outFile))
{
string backupName = $"{outFile}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(outFile, backupName);
LogTarget.LogLine($"Creating backup of old {outFile}", LogEvent.ELogLevel.Info, "ExportProcess");
XmlData.CreateBackup(outFile, true, "ExportProcess", true);
}
LogTarget.StepStarted(2, $"Packing {ImportExportSettings.ZipFile} ({filenames.Length} files)");
// 'using' statements guarantee the stream is closed properly which is a big source
// of problems otherwise. Its exception safe as well which is great.
using (ZipOutputStream s = new ZipOutputStream(File.Create(outFile)))
{
s.SetLevel(9); // 0 - store only to 9 - means best compression
s.Password = MemberImportSettings.ZipPassword; //null is a desired value for "no encryption"
s.SetLevel(9); // 0 - store only ... 9 - best compression
s.Password = ImportExportSettings.ZipPassword; //null is a desired value for "no encryption"
byte[] buffer = new byte[4096];
foreach (string file in filenames)
{
Console.WriteLine(file);
//LogTarget.LogLine($"Packing {file}", LogEvent.ELogLevel.Trace, "ExportProcess");
// Using GetFileName makes the result compatible with XP
// as the resulting path is not absolute.
var entry = new ZipEntry(Path.GetFileName(file));
@ -93,35 +115,104 @@ namespace dezentrale.core
}
catch (Exception ex)
{
Console.WriteLine($"Exception during export: {ex.Message}");
LogTarget.LogLine($"Exception during packing: {ex.Message}", LogEvent.ELogLevel.Error, "ExportProcess");
// No need to rethrow the exception as for our purposes its handled.
return false;
}
if (MemberImportSettings.GpgEnabled)
if (ImportExportSettings.GpgEnabled)
{
Console.WriteLine($"Export: Using GPG to encrypt {Path.Combine(OutputDir, MemberImportSettings.GpgFile)}");
if (!Gpg($"--output \"{Path.Combine(OutputDir, MemberImportSettings.GpgFile)}\" -c \"{tmpFile}\"", MemberImportSettings.GpgPassword)) return false;
tmpFile = Path.Combine(OutputDir, MemberImportSettings.GpgFile);
LogTarget.StepStarted(3, $"Encrypting {ImportExportSettings.GpgFile}");
LogTarget.LogLine($"Using GPG to encrypt {Path.Combine(OutputDir, ImportExportSettings.GpgFile)}", LogEvent.ELogLevel.Info, "ExportProcess");
if (!Gpg($"--output \"{Path.Combine(OutputDir, ImportExportSettings.GpgFile)}\" -c \"{outFile}\"", ImportExportSettings.GpgPassword, LogTarget)) return false;
outFile = Path.Combine(OutputDir, ImportExportSettings.GpgFile);
}
if (MemberImportSettings.HgEnabled)
LogTarget.StepStarted(4, $"Committing and pushing");
if (ImportExportSettings.HgEnabled)
{
Console.WriteLine($"Export: Using HG to commit / push {tmpFile}");
LogTarget.LogLine($"Using HG to commit / push {outFile}", LogEvent.ELogLevel.Info, "ExportProcess");
//this might fail as repo might be existing / file might be already in repo
RunProcess("hg", "init", OutputDir);
RunProcess("hg", $"add {tmpFile}", OutputDir);
RunProcess("hg", "init", OutputDir, LogTarget);
RunProcess("hg", $"add {outFile}", OutputDir, LogTarget);
//now, committing is more interesting
if (!RunProcess("hg",
"commit"
+ $" --message \"dezentrale-members.exe --mode=export\nProgram version={Program.VersionString}\""
+ $" --user \"{MemberImportSettings.HgUserName}\"", OutputDir))
+ $" --user \"{ImportExportSettings.HgUserName}\"", OutputDir, LogTarget))
return false;
if (!RunProcess("hg", $"--config auth.rc.prefix={MemberImportSettings.HgURL} --config auth.rc.username={MemberImportSettings.HgUserName} --config auth.rc.password={MemberImportSettings.HgPassword} push {MemberImportSettings.HgURL}", OutputDir))
if (!RunProcess("hg", $"--config auth.rc.prefix={ImportExportSettings.HgURL} --config auth.rc.username={ImportExportSettings.HgUserName} --config auth.rc.password={ImportExportSettings.HgPassword} push {ImportExportSettings.HgURL}", OutputDir, LogTarget))
return false;
}
//TBD: Validate
LogTarget.StepStarted(5, $"Validating the exported data");
//extract all to
/*string verifyDirectory = Path.Combine(memberDirectory, "verify");
try { Directory.CreateDirectory(verifyDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating verify directory:\n{ex.Message}"); return false; }
//Move all *.xml to *.bak in verify directory
string[] filenames = Directory.GetFiles(verifyDirectory, "*.xml");
foreach (string f in filenames)
{
string fileName = Path.Combine(verifyDirectory, f);
string backupName = $"{fileName}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(fileName, backupName);
File.Delete(fileName);
}
if (!Import(verifyDirectory, outputDir)) return false;
try
{
Console.WriteLine("Verify: Checking files");
filenames = Directory.GetFiles(memberDirectory, "*.xml");
foreach (string fileWithPath in filenames)
{
string fileName = Path.GetFileName(fileWithPath);
Console.WriteLine($"Checking for {fileName}");
string origFile = Path.Combine(memberDirectory, fileName);
string compareFile = Path.Combine(verifyDirectory, fileName);
if (!File.Exists(compareFile))
{
Console.WriteLine($"File doesn't exist: {compareFile}");
return false;
}
if (!FilesCompare(origFile, compareFile))
{
Console.WriteLine($"File comparison failed between: \"{compareFile}\" and \"{compareFile}\"");
return false;
}
}
filenames = Directory.GetFiles(verifyDirectory, "*.xml");
foreach (string fileWithPath in filenames)
{
string fileName = Path.GetFileName(fileWithPath);
string origFile = Path.Combine(memberDirectory, fileName);
string compareFile = Path.Combine(verifyDirectory, fileName);
if (!File.Exists(origFile))
{
Console.WriteLine($"Found extra xml in verify folder: {compareFile}");
return false;
}
}
Console.WriteLine("Verify: Done. All OK");
}
catch (Exception ex)
{
Console.WriteLine($"Exception during verify: {ex.Message}");
// No need to rethrow the exception as for our purposes its handled.
return false;
}*/
return true;
}
}

View File

@ -6,15 +6,15 @@ namespace dezentrale.core
{
public abstract class ImportExportBase : BackgroundProcess
{
public model.MemberImportExport MemberImportSettings { get; set; } = null;
public model.MemberImportExport ImportExportSettings { get; set; } = null;
public string MemberDir { get; set; } = null; //! Directory that holds the application settings
public string InputDir { get; set; } = null; //! Import working directory
public string OutputDir { get; set; } = null; //! Export working directory
public static bool Gpg(string args, string gpgPassword)
public static bool Gpg(string args, string gpgPassword, core.ILogger log = null)
{
string argsFull = $"--batch --yes --passphrase \"{gpgPassword}\" {args}";
return RunProcess("gpg", argsFull);
return RunProcess("gpg", argsFull, ".", log);
}
public static bool RunProcess(string cmd, string args, string workingDir = ".", core.ILogger log = null)
@ -24,7 +24,7 @@ namespace dezentrale.core
if (log != null)
{
log.LogLine($"Running {cmd}", model.LogEvent.ELogLevel.Info, "RunProcess");
log.LogRaw($"args: {cmd} {args}");
log.LogRaw($"args: {args}");
log.LogRaw($"dir: {workingDir}");
}
else
@ -41,10 +41,28 @@ namespace dezentrale.core
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
string stdout;
string stderr;
bool toReturn;
//For testing the import/export, the versioning can be omitted by using gpgOnly = true.
bool gpgOnly = false;
if (gpgOnly && !cmd.Equals("gpg"))
{
stdout = "std\r\nout";
stderr = "std\r\nerr";
Thread.Sleep(2000);
toReturn = true;
} else
{
p.Start();
stdout = p.StandardOutput.ReadToEnd();
stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
toReturn = p.ExitCode == 0;
}
if (stdout.Length > 0)
{
if (log != null) log.LogRaw(stdout);
@ -65,7 +83,7 @@ namespace dezentrale.core
Console.WriteLine();
}
}
return p.ExitCode == 0;
return toReturn;
}
catch (Exception ex)
{

View File

@ -11,28 +11,39 @@ namespace dezentrale.core
public ImportProcess()
{
Caption = "Database import";
Steps = 4;
Steps = 5;
}
protected override bool Run()
{
LogTarget.StepStarted(0, "Preparing import");
if (MemberImportSettings == null)
if (ImportExportSettings == null)
{
LogTarget.LogLine("MemberImportExport data class not set.", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
if (MemberDir == null)
{
LogTarget.LogLine("Member directory not set.", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
} else if (!Directory.Exists(MemberDir))
{
LogTarget.LogLine($"Cannot find directory '{MemberDir}'", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
if (InputDir == null)
{
LogTarget.LogLine("Input directory not set.", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
else if (!Directory.Exists(InputDir))
{
LogTarget.LogLine($"Cannot find directory '{InputDir}'", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
@ -40,63 +51,50 @@ namespace dezentrale.core
LogTarget.StepStarted(1, "Fetching repository");
if (MemberImportSettings.HgEnabled)
if (ImportExportSettings.HgEnabled)
{
RunProcess("hg", "init", InputDir, LogTarget);
RunProcess("hg", "update null", InputDir, LogTarget);
if (!RunProcess("hg", $"--config auth.rc.prefix={MemberImportSettings.HgURL} --config auth.rc.username={MemberImportSettings.HgUserName} --config auth.rc.password={MemberImportSettings.HgPassword} pull {MemberImportSettings.HgURL}", InputDir, LogTarget))
if (!RunProcess("hg", $"--config auth.rc.prefix={ImportExportSettings.HgURL} --config auth.rc.username={ImportExportSettings.HgUserName} --config auth.rc.password={ImportExportSettings.HgPassword} pull {ImportExportSettings.HgURL}", InputDir, LogTarget))
return false;
if (!RunProcess("hg", $"update", InputDir, LogTarget))
return false;
}
if (MemberImportSettings.GpgEnabled)
if (ImportExportSettings.GpgEnabled)
{
Console.WriteLine($"Import: Using GPG to decrypt {Path.Combine(InputDir, MemberImportSettings.GpgFile)}");
if (!Gpg($"--output {Path.Combine(InputDir, MemberImportSettings.ZipFile)} --decrypt {Path.Combine(InputDir, MemberImportSettings.GpgFile)}", MemberImportSettings.GpgPassword)) return false;
}
if (!Directory.Exists(MemberDir))
{
LogTarget.LogLine($"Cannot find directory '{MemberDir}'", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
if (!Directory.Exists(InputDir))
{
LogTarget.LogLine($"Cannot find directory '{InputDir}'", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
LogTarget.StepStarted(2, $"Decrypting {ImportExportSettings.GpgFile}");
LogTarget.LogLine($"Import: Using GPG to decrypt {Path.Combine(InputDir, ImportExportSettings.GpgFile)}", LogEvent.ELogLevel.Info, "ImportProcess");
if (!Gpg($"--output {Path.Combine(InputDir, ImportExportSettings.ZipFile)} --decrypt {Path.Combine(InputDir, ImportExportSettings.GpgFile)}", ImportExportSettings.GpgPassword, LogTarget)) return false;
}
try
{
LogTarget.StepStarted(2, $"Backupping Contents of {MemberDir}");
LogTarget.StepStarted(3, $"Backupping Contents of {MemberDir}");
string[] filenames = Directory.GetFiles(MemberDir, "*.xml");
LogTarget.LogLine($"Renaming {filenames.Length} xml files to xml.bak in {MemberDir}", LogEvent.ELogLevel.Info, "ImportProcess");
LogTarget.LogLine($"Backing up all xml in {MemberDir} ({filenames.Length} files)", LogEvent.ELogLevel.Info, "ImportProcess");
foreach (string f in filenames)
{
string fileName = Path.GetFileName(f);
string backupName = $"{fileName}.bak";
if (File.Exists(backupName))
{
LogTarget.LogLine($"Deleting previous {backupName}", LogEvent.ELogLevel.Trace, "ImportProcess");
File.Delete(backupName);
}
LogTarget.LogLine($"Renaming {fileName} ({f}) to {backupName}", LogEvent.ELogLevel.Trace, "ImportProcess");
File.Move(fileName, backupName);
LogTarget.LogLine($"Deleting backupped {fileName}", LogEvent.ELogLevel.Trace, "ImportProcess");
File.Delete(fileName);
//LogTarget.LogLine($"Creating backup of {f}", LogEvent.ELogLevel.Trace, "ImportProcess");
XmlData.CreateBackup(f, false, "DbImport", true);
}
foreach (string f in filenames)
{
//LogTarget.LogLine($"Deleting backupped {f}", LogEvent.ELogLevel.Trace, "ImportProcess");
File.Delete(f);
}
System.Threading.Thread.Sleep(10);
LogTarget.StepStarted(3, $"Unpacking {MemberImportSettings.ZipFile}");
LogTarget.LogLine($"Extracting {Path.Combine(InputDir, MemberImportSettings.ZipFile)}", LogEvent.ELogLevel.Info, "ImportProcess");
string inFile = Path.Combine(InputDir, MemberImportSettings.ZipFile);
LogTarget.StepStarted(4, $"Unpacking {ImportExportSettings.ZipFile}");
LogTarget.LogLine($"Extracting {Path.Combine(InputDir, ImportExportSettings.ZipFile)}", LogEvent.ELogLevel.Info, "ImportProcess");
string inFile = Path.Combine(InputDir, ImportExportSettings.ZipFile);
using (ZipInputStream s = new ZipInputStream(File.OpenRead(inFile)))
{
s.Password = MemberImportSettings.ZipPassword;
s.Password = ImportExportSettings.ZipPassword;
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
@ -136,7 +134,7 @@ namespace dezentrale.core
}
}
}
LogTarget.StepCompleted(3, $"Unpacking {MemberImportSettings.ZipFile}", true);
LogTarget.StepCompleted(4, $"Unpacking {ImportExportSettings.ZipFile}", true);
}
catch (Exception ex)
{

View File

@ -13,6 +13,8 @@ namespace dezentrale.model
[XmlElement] public MemberImportExport ImportExport{ get; set; } = new MemberImportExport();
[XmlElement] public string DbDirectory { get; set; } = DefaultDbDirectory;
//[XmlElement] public string DbBackupDirectory { get; set; } = DefaultDbBackupDirectory;
//[XmlElement] public string ImportExportDirectory { get; set; } = DefaultImportExportDirectory;
[XmlElement] public uint RegularPaymentAmount { get; set; } = 3200; //cents
[XmlElement] public string RegularPaymentCurrency { get; set; } = "EUR";
[XmlElement] public string LocalUser { get; set; } = "John Doe";
@ -26,6 +28,8 @@ namespace dezentrale.model
[XmlElement] public List<KeyValue> MoneyTransferRegEx { get; set; } = new List<KeyValue>(); //This doesn't belong here! Move to new file within db-data!
[XmlElement] public DateTime LastCronjobRun { get; set; } = DateTime.Now; //This doesn't belong here! Move to new file within db-data!
[XmlIgnore] public static string DefaultDbDirectory{ get; private set; } = "db-data";
[XmlIgnore] public static string DefaultDbDirectory { get; private set; } = "db-data";
//[XmlIgnore] public static string DefaultDbBackupDirectory { get; private set; } = "db-backup";
//[XmlIgnore] public static string DefaultImportExportDirectory { get; private set; } = "import-export";
}
}

View File

@ -21,34 +21,6 @@ namespace dezentrale.model
[XmlElement] public string GitUserName { get; set; } = "";
[XmlElement] public string GitPassword { get; set; } = "";
[Obsolete]
public bool Export(string memberDirectory, string outputDir)
{
throw new NotImplementedException();
}
[Obsolete]
public bool Import(string memberDirectory, string inputDir)
{
throw new NotImplementedException();
/*if(HgEnabled)
{
RunProcess("hg", "init", inputDir);
RunProcess("hg", "update null", inputDir);
if (!RunProcess("hg", $"--config auth.rc.prefix={HgURL} --config auth.rc.username={HgUserName} --config auth.rc.password={HgPassword} pull {HgURL}", inputDir))
return false;
if (!RunProcess("hg", $"update", inputDir))
return false;
}
if (GpgEnabled)
{
Console.WriteLine($"Import: Using GPG to decrypt {Path.Combine(inputDir, GpgFile)}");
if (!Gpg($"--output {Path.Combine(inputDir, ZipFile)} --decrypt {Path.Combine(inputDir, GpgFile)}", GpgPassword)) return false;
}
Console.WriteLine($"Import: Extracting {Path.Combine(inputDir, ZipFile)}");
if (ZipImport(memberDirectory, inputDir) != true) return false;
return true;*/
}
private bool FilesCompare(string file1, string file2)
{
try
@ -68,85 +40,5 @@ namespace dezentrale.model
}
return true;
}
[Obsolete]
public bool VerifyExport(string memberDirectory, string outputDir)
{
if (!Directory.Exists(memberDirectory))
{
Console.WriteLine($"Cannot find directory '{memberDirectory}'");
return false;
}
if (!Directory.Exists(outputDir))
{
Console.WriteLine($"Cannot find directory '{outputDir}'");
return false;
}
Console.WriteLine("Verifying exported");
//extract all to
string verifyDirectory = Path.Combine(memberDirectory, "verify");
try { Directory.CreateDirectory(verifyDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating verify directory:\n{ex.Message}"); return false; }
//Move all *.xml to *.bak in verify directory
string[] filenames = Directory.GetFiles(verifyDirectory, "*.xml");
foreach (string f in filenames)
{
string fileName = Path.Combine(verifyDirectory, f);
string backupName = $"{fileName}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(fileName, backupName);
File.Delete(fileName);
}
if (!Import(verifyDirectory, outputDir)) return false;
try
{
Console.WriteLine("Verify: Checking files");
filenames = Directory.GetFiles(memberDirectory, "*.xml");
foreach (string fileWithPath in filenames)
{
string fileName = Path.GetFileName(fileWithPath);
Console.WriteLine($"Checking for {fileName}");
string origFile = Path.Combine(memberDirectory, fileName);
string compareFile = Path.Combine(verifyDirectory, fileName);
if (!File.Exists(compareFile))
{
Console.WriteLine($"File doesn't exist: {compareFile}");
return false;
}
if (!FilesCompare(origFile, compareFile))
{
Console.WriteLine($"File comparison failed between: \"{compareFile}\" and \"{compareFile}\"");
return false;
}
}
filenames = Directory.GetFiles(verifyDirectory, "*.xml");
foreach (string fileWithPath in filenames)
{
string fileName = Path.GetFileName(fileWithPath);
string origFile = Path.Combine(memberDirectory, fileName);
string compareFile = Path.Combine(verifyDirectory, fileName);
if (!File.Exists(origFile))
{
Console.WriteLine($"Found extra xml in verify folder: {compareFile}");
return false;
}
}
Console.WriteLine("Verify: Done. All OK");
}
catch (Exception ex)
{
Console.WriteLine($"Exception during verify: {ex.Message}");
// No need to rethrow the exception as for our purposes its handled.
return false;
}
return true;
}
}
}

View File

@ -10,7 +10,36 @@ namespace dezentrale.model
public class XmlData
{
[XmlAttribute] public DateTime LastChanged { get; set; } = DateTime.Now;
[XmlAttribute] public string ProgramVersion { get; set; } = "";
[XmlAttribute] public string ProgramVersion { get; set; } = "";
/** \brief Move or make a backup copy of the specified file to the same folder. Will overwrite old backups if @ref permanentWithTimestamp is false
* \param name="fileWithPath" Source file to copy. File must exist.
* \param name="backupName" Optional name for a backup. E.g. "PreImport" or "NewProgVersion"
* \param param name="permanentWithTimestamp" Stores the backup including a timestamp (@ref DateTime.Now) and fails if the target file already exists.
* \return the resulting name on success.
* \note this method throws Exceptions when failing.
*/
public static string CreateBackup(string fileWithPath, bool fileMove = true, string backupName = null, bool permanentWithTimestamp = false)
{
if (!File.Exists(fileWithPath)) throw new FileNotFoundException(fileWithPath);
string backupFile = fileWithPath;
if (backupName != null) backupFile += "." + backupName;
if (permanentWithTimestamp) backupFile += "." + DateTime.Now.ToString("yyMMdd_HHmmss");
backupFile += ".bak";
if (File.Exists(backupFile))
{
if (permanentWithTimestamp)
throw new IOException($"File {backupFile} already exists");
File.Delete(backupFile);
}
if (fileMove) File.Move(fileWithPath, backupFile);
else File.Copy(fileWithPath, backupFile);
return backupName;
}
public static XmlData LoadFromFile(string fileName, Type type = null)
{
@ -26,10 +55,14 @@ namespace dezentrale.model
{
Console.WriteLine($"Object of type {ds.GetType()} was stored in Version {ds.ProgramVersion:X8}, Re-Storing with {Program.VersionNumber:X8}");
//backup file
string backupName = $"{fileName}.v{ds.ProgramVersion:X8}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(fileName, backupName);
if (!SaveToFile(fileName, ds)) throw new Exception("Saving returned false");
try
{
CreateBackup(fileName, true, $"v{ds.ProgramVersion:X8}", true);
if (!SaveToFile(fileName, ds)) throw new Exception("Saving returned false");
} catch(Exception e2)
{
Console.WriteLine($"Error {e2.GetType()}: {e2.Message}");
}
}
return ds;
}
@ -48,9 +81,10 @@ namespace dezentrale.model
if (File.Exists(fileName))
{
string backupName = $"{fileName}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(fileName, backupName);
CreateBackup(fileName);
//string backupName = $"{fileName}.bak";
//if (File.Exists(backupName)) File.Delete(backupName);
//File.Move(fileName, backupName);
}
Console.WriteLine($"XmlData.SaveToFile({ds.GetType()})");
ds.ProgramVersion = Program.VersionString;

View File

@ -121,16 +121,14 @@ namespace dezentrale.view
}
private void mnuMain_File_Export(object sender, EventArgs e)
{
if (!Program.config.ImportExport.Export(Program.config.DbDirectory, Program.DmDirectory))
{
MessageBox.Show("Export failed!");
return;
}
if (!Program.config.ImportExport.VerifyExport(Program.config.DbDirectory, Program.DmDirectory))
{
MessageBox.Show("Export verify failed!");
return;
}
ExportProcess export = new ExportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
OutputDir = Program.DmDirectory,
};
frmProcessWithLog frmImport = new frmProcessWithLog(export, false);
frmImport.ShowDialog();
}
private void mnuMain_File_Import(object sender, EventArgs e)
@ -140,7 +138,7 @@ namespace dezentrale.view
{
ImportProcess import = new ImportProcess()
{
MemberImportSettings = Program.config.ImportExport,
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
InputDir = Program.DmDirectory,
};