283 lines
9.6 KiB
C#
283 lines
9.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BeWoDatabaseUpdater.Extensions;
|
|
using BeWoDatabaseUpdater.Utils;
|
|
|
|
namespace BeWoDatabaseUpdater
|
|
{
|
|
// ToDo: bestimmte Fehlermeldungen ignorieren oder prüfen, ob es die Spalten bereits gibt etc.
|
|
internal class Program
|
|
{
|
|
private const int CutoffYear = 2001;
|
|
private static string _ConnectionString;
|
|
private static string _ModelPath;
|
|
private static DateTime? _LastAccessTime;
|
|
|
|
private const string UpdaterSettingsFilePath = "bewo-database-updater-settings.txt";
|
|
public const string FailedSqlCommandsFilePath = "bewo-database-updater-failed-sql-commands.txt";
|
|
|
|
private static readonly List<FilePath2MySqlCommands> _FilePaths2Sql = [];
|
|
private static List<string> _FilePaths = [];
|
|
private static List<string> _BeWoSchemaNames = [];
|
|
private static readonly List<DateTime> _LastAccessTimes = [];
|
|
private static readonly Stopwatch _Stopwatch = new();
|
|
|
|
private static int _OpenDbConnections = 0;
|
|
|
|
private static async Task Main(string[] args)
|
|
{
|
|
var settingsFilePath = Path.Combine(AppContext.BaseDirectory, UpdaterSettingsFilePath);
|
|
|
|
// Falls die Settings-Datei noch nicht existiert:
|
|
if(false == File.Exists(settingsFilePath))
|
|
{
|
|
using var fileStream = File.Create(settingsFilePath);
|
|
}
|
|
|
|
// Falls es noch keine Datei mit Sql-Fehler gibt, wird eine erstellt, in die die Fehler geschrieben werden:
|
|
if(false == File.Exists(FailedSqlCommandsFilePath))
|
|
{
|
|
using var fileStream = File.Create(FailedSqlCommandsFilePath);
|
|
}
|
|
|
|
// Die Settingsdatei mit Pfad zum "Model"-Verzeichnis, MySql-Connection-String und dem letzten Ausführdatum auslesen
|
|
ReadSettingsFile(settingsFilePath);
|
|
|
|
if(string.IsNullOrWhiteSpace(_ConnectionString))
|
|
{
|
|
Console.WriteLine();
|
|
Console.Write("Connection String (Server, User Id, Passwort): ");
|
|
_ConnectionString = Console.ReadLine();
|
|
}
|
|
|
|
// Den Pfad zum Model-Verzeichnis im BeWoPlaner-Projekt ermitteln
|
|
DetermineModelPath();
|
|
|
|
// Die Dateien mit den Sql-Skripten auflisten
|
|
_Stopwatch.Start();
|
|
GetTextAndSqlFiles();
|
|
|
|
Console.WriteLine($"{DateTime.Now:dd.MM.yyyy HH:mm:ss.fff}: Führe Updates durch ...{Environment.NewLine}");
|
|
|
|
_BeWoSchemaNames = ["3522103738"]; //await MySqlBeWoHelper.LoadBeWoDatabaseNames(_ConnectionString) ?? [];
|
|
|
|
LoadSqlScriptsFromFilesToMemory(() =>
|
|
{
|
|
var commandCount = 0;
|
|
var fileCount = 0;
|
|
|
|
_FilePaths2Sql.DoForEach(path2Commands =>
|
|
{
|
|
if(path2Commands is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
commandCount += path2Commands.Commands.Count;
|
|
fileCount++;
|
|
});
|
|
|
|
var message = $"{DateTime.Now:dd.MM.yyyy HH:mm:ss.fff}: {commandCount} MySQL-Abfrag{(commandCount != 1 ? "en" : string.Empty)} in {fileCount} Datei{(fileCount != 1 ? "en" : string.Empty)} und {_BeWoSchemaNames.Count} BeWoPlaner-Datenbanken ({_BeWoSchemaNames.Count * commandCount} Transaktionen gesamt):{Environment.NewLine}";
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
for(var i = 0; i < message.Length; i++)
|
|
{
|
|
sb.Append('-');
|
|
}
|
|
|
|
Console.WriteLine($"{message}{sb}");
|
|
|
|
if(commandCount == 0)
|
|
{
|
|
OnAllThreadsCompleted();
|
|
return;
|
|
}
|
|
|
|
// Ein Thread pro Sql-Kommando
|
|
// ToDo: Threads beachten!
|
|
var threads = new List<Thread>();
|
|
|
|
foreach(var schemaName in _BeWoSchemaNames)
|
|
{
|
|
foreach(var path2Commands in _FilePaths2Sql)
|
|
{
|
|
_LastAccessTimes.Add(new FileInfo(path2Commands.FilePath).LastAccessTime);
|
|
|
|
foreach(var command in path2Commands.Commands)
|
|
{
|
|
var thread = new Thread(() =>
|
|
{
|
|
var sql = $"USE `{schemaName}`; {command}";
|
|
|
|
MySqlBeWoHelper.ExecuteUpdateOrCreateAsync(sql, path2Commands.FilePath, _ConnectionString);
|
|
});
|
|
|
|
thread.Start();
|
|
|
|
threads.Add(thread);
|
|
}
|
|
}
|
|
}
|
|
|
|
threads.DoForEach(thread =>
|
|
{
|
|
thread.Join();
|
|
|
|
OnAllThreadsCompleted();
|
|
});
|
|
});
|
|
|
|
#if DEBUG
|
|
Console.Read();
|
|
#endif
|
|
|
|
if(MySqlBeWoHelper.DistinctErrors.Any())
|
|
{
|
|
Console.Read();
|
|
}
|
|
}
|
|
|
|
private static void OnAllThreadsCompleted()
|
|
{
|
|
_LastAccessTime = _LastAccessTimes.Any() ? _LastAccessTimes.Max() : DateTime.Now;
|
|
|
|
_Stopwatch.Stop();
|
|
|
|
File.WriteAllText(UpdaterSettingsFilePath,
|
|
$"ConnectionString={_ConnectionString}{Environment.NewLine}" +
|
|
$"LastScriptAccessTime={_LastAccessTime}{Environment.NewLine}" +
|
|
$"ModelPath={_ModelPath}"
|
|
);
|
|
|
|
var timeSpan = TimeSpan.FromTicks(_Stopwatch.ElapsedTicks);
|
|
|
|
Console.WriteLine($"{DateTime.Now:dd.MM.yyyy HH:mm:ss.fff}: Dauer: {timeSpan.ToShortString()}{Environment.NewLine}");
|
|
|
|
Console.WriteLine($"{MySqlBeWoHelper.DistinctErrors.Count} Fehler{(MySqlBeWoHelper.DistinctErrors.Any() ? ":" : "")}");
|
|
|
|
//MySqlBeWoHelper.WriteSqlErrorsToFile();
|
|
|
|
MySqlBeWoHelper.DistinctErrors.DoForEach(number2Message => Console.WriteLine($"{number2Message.Key}: {number2Message.Value}"));
|
|
|
|
Console.WriteLine("Alle Updates durchgeführt!");
|
|
}
|
|
|
|
private static void GetTextAndSqlFiles()
|
|
{
|
|
_FilePaths = Directory.GetFiles(_ModelPath).Where(file =>
|
|
{
|
|
var extension = Path.GetExtension(file);
|
|
|
|
var fileInfo = new FileInfo(file);
|
|
|
|
var name = fileInfo.Name.ToLower();
|
|
|
|
if(false == name.StartsWith("changes_"))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int.TryParse(name.Split('_')[1], out var year);
|
|
|
|
if(year == 0)
|
|
{
|
|
year = DateTime.Today.Year;
|
|
}
|
|
|
|
return (extension.EndsWith("txt") || extension.EndsWith("sql")) && year >= CutoffYear && fileInfo.LastAccessTime > _LastAccessTime;
|
|
}).ToList();
|
|
}
|
|
|
|
private static void ReadSettingsFile(string settingsFilePath)
|
|
{
|
|
var allLines = File.ReadAllLines(settingsFilePath);
|
|
|
|
foreach(var line in allLines)
|
|
{
|
|
var settingsName2Value = line.Split('=');
|
|
|
|
if(settingsName2Value.Length < 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var settingsName = settingsName2Value[0];
|
|
|
|
var indexOfFirstEquals = line.IndexOf('=');
|
|
|
|
var settingsValue = line.Substring(indexOfFirstEquals + 1);
|
|
|
|
switch(settingsName)
|
|
{
|
|
case "ConnectionString":
|
|
_ConnectionString = settingsValue;
|
|
break;
|
|
case "LastScriptAccessTime":
|
|
if(DateTime.TryParse(settingsValue, out var parsedNewestScriptCreationTime))
|
|
{
|
|
_LastAccessTime = parsedNewestScriptCreationTime;
|
|
}
|
|
break;
|
|
case "ModelPath":
|
|
_ModelPath = settingsValue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void DetermineModelPath()
|
|
{
|
|
while(string.IsNullOrWhiteSpace(_ModelPath) || false == Directory.Exists(_ModelPath))
|
|
{
|
|
Console.WriteLine();
|
|
|
|
if(false == string.IsNullOrWhiteSpace(_ModelPath) && false == Directory.Exists(_ModelPath))
|
|
{
|
|
Console.WriteLine($"Der Pfad '{_ModelPath}' ist ungültig!");
|
|
}
|
|
|
|
Console.Write("Pfad zum Model-Verzeichnis: ");
|
|
_ModelPath = Console.ReadLine();
|
|
}
|
|
}
|
|
|
|
private static void LoadSqlScriptsFromFilesToMemory(Action callback)
|
|
{
|
|
var threads = new List<Thread>();
|
|
|
|
foreach(var filePath in _FilePaths)
|
|
{
|
|
var thread = new Thread(() =>
|
|
{
|
|
var fileInfo = new FileInfo(filePath);
|
|
|
|
if(_LastAccessTime.HasValue && _LastAccessTime >= fileInfo.CreationTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_FilePaths2Sql.Add(new FilePath2MySqlCommands(filePath, File.ReadAllText(filePath).Split(';').ToList()));
|
|
});
|
|
|
|
thread.Start();
|
|
|
|
threads.Add(thread);
|
|
}
|
|
|
|
Task.Run(() =>
|
|
{
|
|
threads.DoForEach(thread => thread.Join());
|
|
|
|
callback?.Invoke();
|
|
});
|
|
}
|
|
}
|
|
}
|