191201PX Refactoring database import to use process window/logging; unfinished yet.

This commit is contained in:
phantomix 2019-12-02 13:15:33 +01:00
parent 575279e0c2
commit 7a65a110fc
5 changed files with 245 additions and 60 deletions

View File

@ -31,7 +31,7 @@ namespace dezentrale
{
public class Program
{
public static uint VersionNumber { get; private set; } = 0x19112700;
public static uint VersionNumber { get; private set; } = 0x19120100;
public static string VersionString { get; private set; } = $"{VersionNumber:x}";
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

View File

@ -27,8 +27,19 @@ namespace dezentrale.model
EMail,
// TODO: [Obsolete("Use ELogLevel.Error instead")]
Error,
}
public enum ELogLevel
{
Trace = -1,
Debug = 0,
Info = 1,
Warning = 2,
Error = 3,
}
[XmlAttribute] public DateTime Timestamp { get; set; } = DateTime.Now;
[XmlAttribute] public string LocalUser { get; set; } = Program.config.LocalUser;
[XmlElement("SubEvent")] public List<LogSubEvent> SubEvents { get; set; } = new List<LogSubEvent>();

View File

@ -8,39 +8,156 @@ namespace dezentrale.model
{
public class ImportProcess : view.BackgroundProcess
{
public MemberImportExport MemberImportSettings { get; set; } = null;
public string MemberDir { get; set; } = null;
public string InputDir { get; set; } = null;
public ImportProcess()
{
Caption = "Database import";
Steps = 20;
Steps = 4;
}
protected override bool Run()
{
if (InputDir == null)
{
LogTarget.LogLine("Input directory not set.", view.ELogLevel.Error, "ImportProcess");
{
LogTarget.StepStarted(0, "Preparing import");
if (MemberImportSettings == 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;
}
if (InputDir == null)
{
LogTarget.LogLine("Input directory not set.", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
/*if (HgEnabled)
LogTarget.StepStarted(1, "Fetching repository");
if (MemberImportSettings.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))
MemberImportExport.RunProcess("hg", "init", InputDir, LogTarget);
MemberImportExport.RunProcess("hg", "update null", InputDir, LogTarget);
if (!MemberImportExport.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))
return false;
if (!RunProcess("hg", $"update", inputDir))
if (!MemberImportExport.RunProcess("hg", $"update", InputDir, LogTarget))
return false;
}
if (GpgEnabled)
if (MemberImportSettings.GpgEnabled)
{
Console.WriteLine($"Import: Using GPG to decrypt {Path.Combine(inputDir, GpgFile)}");
if (!Gpg($"--output {Path.Combine(inputDir, ZipFile)} --decrypt {Path.Combine(inputDir, GpgFile)}")) return false;
Console.WriteLine($"Import: Using GPG to decrypt {Path.Combine(InputDir, MemberImportSettings.GpgFile)}");
if (!MemberImportExport.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;
}
try
{
LogTarget.StepStarted(2, $"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");
foreach (string f in filenames)
{
string fileName = Path.GetFileName(f);
string backupName = $"{fileName}.bak";
if (File.Exists(backupName)) File.Delete(backupName);
File.Move(fileName, backupName);
File.Delete(fileName);
}
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);
using (ZipInputStream s = new ZipInputStream(File.OpenRead(inFile)))
{
s.Password = MemberImportSettings.ZipPassword;
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
Console.WriteLine(theEntry.Name);
string directoryName = Path.GetDirectoryName(theEntry.Name);
string fileName = Path.GetFileName(theEntry.Name);
// create directory
if (directoryName.Length > 0)
{
Directory.CreateDirectory(directoryName);
}
if (fileName != String.Empty)
{
using (FileStream streamWriter = File.Create(Path.Combine(MemberDir, theEntry.Name)))
{
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}
}
}
}
LogTarget.StepCompleted(3, $"Unpacking {MemberImportSettings.ZipFile}", true);
}
catch (Exception ex)
{
LogTarget.LogLine($"Exception during import: {ex.Message}", LogEvent.ELogLevel.Error, "ImportProcess");
return false;
}
Console.WriteLine($"Import: Extracting {Path.Combine(inputDir, ZipFile)}");
if (ZipImport(memberDirectory, inputDir) != true) return false;*/
return true;
}
private bool ZipImport()
{
try
{
}
catch (Exception ex)
{
Console.WriteLine($"Exception during import: {ex.Message}");
// No need to rethrow the exception as for our purposes its handled.
return false;
}
return true;
}
}
public class MemberImportExport
{
@ -59,12 +176,21 @@ namespace dezentrale.model
private bool RunProcess(string cmd, string args, string workingDir = ".")
public static bool RunProcess(string cmd, string args, string workingDir = ".", view.ILogger log = null)
{
try
{
Console.WriteLine($"cmd: {cmd} {args}");
Console.WriteLine($"dir: {workingDir}");
{
if (log != null)
{
log.LogLine($"Running {cmd}", LogEvent.ELogLevel.Info, "RunProcess");
log.LogRaw($"args: {cmd} {args}");
log.LogRaw($"dir: {workingDir}");
}
else
{
Console.WriteLine($"cmd: {cmd} {args}");
Console.WriteLine($"dir: {workingDir}");
}
Process p = new Process();
p.StartInfo.FileName = cmd;
@ -80,15 +206,23 @@ namespace dezentrale.model
p.WaitForExit();
if (stdout.Length > 0)
{
Console.WriteLine("stdout:");
Console.WriteLine(stdout);
Console.WriteLine();
if (log != null) log.LogRaw(stdout);
else
{
Console.WriteLine("stdout:");
Console.WriteLine(stdout);
Console.WriteLine();
}
}
if (stderr.Length > 0)
{
Console.WriteLine("stderr:");
Console.WriteLine(stderr);
Console.WriteLine();
if (log != null) log.LogRaw(stderr);
else
{
Console.WriteLine("stderr:");
Console.WriteLine(stderr);
Console.WriteLine();
}
}
return p.ExitCode == 0;
} catch (Exception ex)
@ -98,9 +232,9 @@ namespace dezentrale.model
return false;
}
private bool Gpg(string args)
public static bool Gpg(string args, string gpgPassword)
{
string argsFull = $"--batch --yes --passphrase \"{GpgPassword}\" {args}";
string argsFull = $"--batch --yes --passphrase \"{gpgPassword}\" {args}";
return RunProcess("gpg", argsFull);
}
public bool Export(string memberDirectory, string outputDir)
@ -111,7 +245,7 @@ namespace dezentrale.model
if (GpgEnabled)
{
Console.WriteLine($"Export: Using GPG to encrypt {Path.Combine(outputDir, GpgFile)}");
if (!Gpg($"--output \"{Path.Combine(outputDir, GpgFile)}\" -c \"{tmpFile}\"")) return false;
if (!Gpg($"--output \"{Path.Combine(outputDir, GpgFile)}\" -c \"{tmpFile}\"", GpgPassword)) return false;
tmpFile = Path.Combine(outputDir, GpgFile);
}
if (HgEnabled)
@ -136,7 +270,8 @@ namespace dezentrale.model
[Obsolete]
public bool Import(string memberDirectory, string inputDir)
{
if(HgEnabled)
throw new NotImplementedException();
/*if(HgEnabled)
{
RunProcess("hg", "init", inputDir);
RunProcess("hg", "update null", inputDir);
@ -148,11 +283,11 @@ namespace dezentrale.model
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)}")) return false;
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;
return true;*/
}
private bool FilesCompare(string file1, string file2)
{
@ -334,11 +469,13 @@ namespace dezentrale.model
}
return true;
}
}
/*
[Obsolete]
private bool ZipImport(string memberDirectory, string inputDir)
{
throw new NotImplementedException();
/*
if (!Directory.Exists(memberDirectory))
{
Console.WriteLine($"Cannot find directory '{memberDirectory}'");
@ -415,6 +552,6 @@ namespace dezentrale.model
return false;
}
return true;
}
}*/
}
}

View File

@ -22,8 +22,6 @@ namespace dezentrale.view
public frmMain()
{
frmProcessWithLog p = new frmProcessWithLog(new HelloWorldProcess(), false);
p.Show();
this.SuspendLayout();
this.Text = $"dezentrale-members Version {Program.VersionString}";
this.StartPosition = FormStartPosition.CenterScreen;
@ -138,11 +136,22 @@ namespace dezentrale.view
{
DialogResult dr = MessageBox.Show("Overwrite database?", "Warning\nImporting database from external source will overwrite all\nlocal changes! Really import?", MessageBoxButtons.YesNo);
if(dr == DialogResult.Yes)
{
if (!Program.config.ImportExport.Import(Program.config.DbDirectory, Program.DmDirectory))
{
ImportProcess import = new ImportProcess()
{
MemberImportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
InputDir = Program.DmDirectory,
};
frmProcessWithLog frmImport = new frmProcessWithLog(import, false);
dr = frmImport.ShowDialog();
MessageBox.Show("DialogResult=" + dr);
//Reload member list
//Reload moneytransfers, if loaded
/*if (!Program.config.ImportExport.Import(Program.config.DbDirectory, Program.DmDirectory))
{
MessageBox.Show("Import failed!");
}
}*/
Application.Restart();
}
}

View File

@ -6,21 +6,15 @@ using System.Text;
using System.Threading;
using System.Windows.Forms;
using dezentrale.model;
namespace dezentrale.view
{
public enum ELogLevel
{
Trace = -1,
Debug = 0,
Info = 1,
Warning = 2,
Error = 3,
}
public interface ILogger
{
void Clear();
void LogLine(string text, ELogLevel logLevel = ELogLevel.Info, string module = "");
void LogRaw(string text);
void LogLine(string text, LogEvent.ELogLevel logLevel = LogEvent.ELogLevel.Info, string module = "");
}
public interface IProcessController : ILogger
@ -65,7 +59,7 @@ namespace dezentrale.view
{
string stepName = ((i & 0x01) == 0) ? "Hello" : "World";
LogTarget.StepStarted(i, stepName);
LogTarget.LogLine(stepName, ELogLevel.Info, "HelloWorldProcess");
LogTarget.LogLine(stepName, LogEvent.ELogLevel.Info, "HelloWorldProcess");
Thread.Sleep(200);
LogTarget.StepCompleted(i, stepName, (i & 0x01) == 0);
Thread.Sleep(200);
@ -75,6 +69,7 @@ namespace dezentrale.view
}
public class frmProcessWithLog : Form, IProcessController
{
private DialogResult toReturn = DialogResult.Cancel;
private TextBox tbLog = null;
private Label lblStepStatus = null;
private PictureBox picStatus = null;
@ -91,10 +86,19 @@ namespace dezentrale.view
private void printline(string line)
{
tbLog.Invoke(new Action(() => tbLog.AppendText(line + "\r\n")));
// tbLog.Invoke(new Action(() =>
tbLog.AppendText(line + "\r\n")
// ))
;
Console.WriteLine(line);
}
public void LogLine(string text, ELogLevel logLevel, string module)
public void LogRaw(string text)
{
printline(text);
}
public void LogLine(string text, LogEvent.ELogLevel logLevel, string module)
{
string output = $"{DateTime.Now} [{module}] {logLevel} {text}";
printline(output);
@ -108,6 +112,12 @@ namespace dezentrale.view
this.Width = 800;
this.Height = 600;
/* if (autoRun)
{
MessageBox.Show("autoRun=true leads to problems with Invoke on gui access from background thread");
this.Close();
return;
}*/
// build GUI
//[TextBox Multiline ]
//[Step display label ]
@ -177,6 +187,8 @@ namespace dezentrale.view
if (autoRun)
btnStart_Click(null,null);
this.FormClosing += (sender, e) => DialogResult = toReturn;
}
private void btnStart_Click(object sender, EventArgs e)
@ -201,18 +213,34 @@ namespace dezentrale.view
public void StepStarted(uint stepNumber, string stepDescription)
{
lblStepStatus.Invoke(new Action(() => lblStepStatus.Text = $"# {stepNumber}/{this.process.Steps} : {stepDescription}"));
// lblStepStatus.Invoke(new Action(() =>
lblStepStatus.Text = $"# {stepNumber + 1}/{this.process.Steps} : {stepDescription}"
// ))
;
}
public void StepCompleted(uint stepNumber, string stepDescription, bool success)
{
lblStepStatus.Invoke(new Action(() => lblStepStatus.Text = $"# {stepNumber}/{this.process.Steps} : Completed({success}) {stepDescription}"));
// lblStepStatus.Invoke(new Action(() =>
lblStepStatus.Text = $"# {stepNumber + 1}/{this.process.Steps} : Completed({success}) {stepDescription}"
// ))
;
}
public void ActionCompleted(bool success)
{
toReturn = success? DialogResult.Yes : DialogResult.No;
btnCancel.Enabled = false;
btnClose.Invoke(new Action(() => btnClose.Enabled = true ));
picStatus.Invoke(new Action(() => picStatus.BackColor = (success ? Color.Green : Color.Red)));
this.Invoke(new Action(() => this.Text = $"Process - {this.process.Caption}" + (success ? " (done)" : " (failed)")));
// btnClose.Invoke(new Action(() =>
btnClose.Enabled = true
// ))
;
// picStatus.Invoke(new Action(() =>
picStatus.BackColor = (success ? Color.Green : Color.Red)
// ))
;
// this.Invoke(new Action(() =>
this.Text = $"Process - {this.process.Caption}" + (success ? " (done)" : " (failed)")
// ))
;
}
}
}