Results of SyntaxCheck -> extra State

This commit is contained in:
Simon Martens
2023-09-10 16:34:49 +02:00
parent 8fd0050cf3
commit 80e593ce7c
16 changed files with 122 additions and 102 deletions

View File

@@ -13,12 +13,10 @@ public class XMLStateController : Controller {
private IHaDocumentWrappper _lib;
private readonly IXMLInteractionService _xmlService;
private readonly IXMLFileProvider _xmlProvider;
private readonly IMonitorLoop _loop;
public XMLStateController(IMonitorLoop loop, IHaDocumentWrappper lib, IXMLInteractionService xmlService, IXMLFileProvider xmlProvider) {
public XMLStateController(IHaDocumentWrappper lib, IXMLInteractionService xmlService, IXMLFileProvider xmlProvider) {
_lib = lib;
_xmlService = xmlService;
_xmlProvider = xmlProvider;
_loop = loop;
}
[HttpGet]
@@ -26,7 +24,6 @@ public class XMLStateController : Controller {
[FeatureGate(Features.AdminService)]
[GenerateAntiforgeryTokenCookie]
public IActionResult Index() {
_loop.StartMonitorLoop();
var library = _lib.GetLibrary();
var roots = _xmlService.GetRootsList();
if (roots == null) return error404();
@@ -39,6 +36,7 @@ public class XMLStateController : Controller {
var model = new XMLStateViewModel("Dateiübersicht", gD, roots, hF, mF, vS) {
ActiveFile = activeF,
SyntaxCheck = _xmlService.Test()
};
return View("~/Views/Admin/Dynamic/XMLState.cshtml", model);
}

View File

@@ -4,10 +4,12 @@ namespace HaWeb.FileHelpers;
public class ConfigurationMonitor {
private System.Timers.Timer? _timer;
private string[] _paths;
private (string, byte[])[]? _h;
private IServiceProvider _serviceProvider;
public ConfigurationMonitor(string[] paths, IServiceProvider services) {
_paths = paths;
_h = _getHash(paths);
_serviceProvider = services;
}
@@ -33,27 +35,25 @@ public class ConfigurationMonitor {
return true;
}
public void InvokeChanged(string[] paths) {
var h = _getHash(paths);
public void InvokeChanged(IHostEnvironment _) {
var h = _getHash(_paths);
if (_timer == null && !isEqual(h, _h)) {
_h = h;
_timer = new(5000) { AutoReset = false };
_timer = new(8000) { AutoReset = false };
_timer.Enabled = true;
_timer.Elapsed += Action;
_timer.Elapsed += OnChanged;
}
}
private void Action(Object source, System.Timers.ElapsedEventArgs e) {
private void OnChanged(Object source, System.Timers.ElapsedEventArgs e) {
Console.WriteLine("Configuration changed (ConfigurationMonitor Class)");
using IServiceScope serviceScope = _serviceProvider.CreateScope();
IServiceProvider provider = serviceScope.ServiceProvider;
var cP = provider.GetRequiredService<IConfiguration>();
var hP = provider.GetRequiredService<IHaDocumentWrappper>();
hP.ParseConfiguration(cP);
var fP = provider.GetRequiredService<IXMLFileProvider>();
fP.Reload(cP);
fP.ParseConfiguration(cP);
// _lifetime.StopApplication();
_timer = null;
}

View File

@@ -10,7 +10,7 @@ public interface IXMLFileProvider {
public IFileInfo? SaveHamannFile(XElement element, string basefilepath, ModelStateDictionary ModelState);
public List<IFileInfo>? GetHamannFiles();
public (DateTime PullTime, string Hash)? GetGitData();
public void Reload(IConfiguration config);
public void ParseConfiguration(IConfiguration config);
public bool HasChanged();
public void DeleteHamannFile(string filename);
public void Scan();

View File

@@ -52,16 +52,16 @@ public class XMLFileProvider : IXMLFileProvider {
// Check if hamann file already is current working tree status
// -> YES: Load up the file via _lib.SetLibrary();
if (_IsAlreadyParsed()) {
_Lib.SetLibrary(_HamannFiles.First(), null, null);
_Lib.SetLibrary(_HamannFiles!.First(), null, null);
if (_Lib.GetLibrary() != null) return;
}
// -> NO: Try to create a new file
var created = xmlservice.TryCreate();
var created = _XMLService.TryCreate();
if (created != null) {
var file = SaveHamannFile(created, _hamannFileProvider.GetFileInfo("./").PhysicalPath, null);
if (file != null) {
_lib.SetLibrary(file, created.Document, null);
_Lib.SetLibrary(file, created.Document, null);
if (_Lib.GetLibrary() != null) return;
}
}
@@ -75,36 +75,32 @@ public class XMLFileProvider : IXMLFileProvider {
// -> There is none? Use Fallback:
else {
var options = new HaWeb.Settings.HaDocumentOptions();
if (_lib.SetLibrary(null, null, null) == null) {
if (_Lib.SetLibrary(null, null, null) == null) {
throw new Exception("Die Fallback Hamann.xml unter " + options.HamannXMLFilePath + " kann nicht geparst werden.");
}
}
}
public void Reload(IConfiguration config) {
public void ParseConfiguration(IConfiguration config) {
_Branch = config.GetValue<string>("RepositoryBranch");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
_hamannFileProvider = new PhysicalFileProvider(config.GetValue<string>("HamannFileStoreWindows"));
_bareRepositoryFileProvider = new PhysicalFileProvider(config.GetValue<string>("BareRepositoryPathWindows"));
_workingTreeFileProvider = new PhysicalFileProvider(config.GetValue<string>("WorkingTreePathWindows"));
}
else {
_hamannFileProvider = new PhysicalFileProvider(config.GetValue<string>("HamannFileStoreLinux"));
_bareRepositoryFileProvider = new PhysicalFileProvider(config.GetValue<string>("BareRepositoryPathLinux"));
_workingTreeFileProvider = new PhysicalFileProvider(config.GetValue<string>("WorkingTreePathLinux"));
}
// Create File Lists; Here and in xmlservice, which does preliminary checking
Scan();
// Reset XMLInteractionService
if (_WorkingTreeFiles != null && _WorkingTreeFiles.Any()) {
_XMLService.Collect(_WorkingTreeFiles);
}
_HamannFiles = _ScanHamannFiles();
if (_HamannFiles != null && _HamannFiles.Select(x => x.Name).Contains(_Lib.GetActiveFile().Name)) {
_Lib.SetLibrary(_Lib.GetActiveFile(), null, null);
if (_Lib.GetLibrary() != null) return;
}
// Failed to reload File, reload it all, same procedure as above:
// Check if hamann file already is current working tree status
// -> YES: Load up the file via _lib.SetLibrary();
if (_IsAlreadyParsed()) {
_Lib.SetLibrary(_HamannFiles.First(), null, null);
_Lib.SetLibrary(_HamannFiles!.First(), null, null);
if (_Lib.GetLibrary() != null) return;
}

View File

@@ -27,13 +27,4 @@ public class FileList {
public List<XMLRootDocument>? GetFileList()
=> this._Files != null ? this._Files.ToList() : null;
public FileList Clone() {
var ret = new FileList(this.XMLRoot);
if (_Files != null)
foreach (var file in _Files) {
ret.Add(file);
}
return ret;
}
}

View File

@@ -1,6 +0,0 @@
namespace HaWeb.Models;
using System.ComponentModel.DataAnnotations;
public class YearSetting {
[Required]
public int EndYear { get; set; }
}

View File

@@ -1,22 +1,22 @@
namespace HaWeb.Models;
public class SyntaxCheckModel {
public string Prefix { get; private set; }
public List<SyntaxError>? Errors { get; set; }
public List<SyntaxError>? Warnings { get; set; }
public string File { get; private set; }
public List<SyntaxError>? Errors { get; private set; }
public SyntaxCheckModel(string prefix) {
Prefix = prefix;
public SyntaxCheckModel(string file) {
File = file;
}
public void Log(int? line, int? column, string msg) {
if (String.IsNullOrWhiteSpace(msg)) return;
if (Errors == null) Errors = new();
// var prefix = DateTime.Now.ToLongDateString() + ": ";
Errors.Add(new SyntaxError(line, column, msg));
}
public void ResetLog() {
Errors = null;
}
}
public class SyntaxError {
public string Message { get; private set; }
public string? File { get; set; }
public string? Line { get; set; }
public string? Column { get; set; }
public SyntaxError(string message) {
Message = message;
}
}

View File

@@ -0,0 +1,13 @@
namespace HaWeb.Models;
public class SyntaxError {
public string Message { get; private set; }
public int? Line { get; set; }
public int? Column { get; set; }
public SyntaxError(int? line, int? column, string message) {
Line = line;
Column = column;
Message = message;
}
}

View File

@@ -19,6 +19,9 @@ public class XMLStateViewModel {
// Verfügbare (Gesamt-)Dateien
public List<IFileInfo>? HamannFiles { get; set; }
// Syntax-Check-Resultate
public Dictionary<string, SyntaxCheckModel>? SyntaxCheck { get; set; }
public XMLStateViewModel(
string title,
(DateTime PullTime, string Hash)? gitData,

View File

@@ -26,8 +26,6 @@ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
builder.Configuration.AddJsonFile(p, optional: true, reloadOnChange: true);
}
// Create initial Data
var tS = new XMLTestService();
var XMLIS = new XMLInteractionService(builder.Configuration, tS);
@@ -59,7 +57,7 @@ var cM = new ConfigurationMonitor(configpaths.ToArray(), app.Services);
ChangeToken.OnChange(
() => app.Configuration.GetReloadToken(),
(state) => cM.InvokeChanged(state),
configpaths.ToArray()
app.Environment
);
// Configure the HTTP request pipeline.

View File

@@ -25,8 +25,18 @@
<td>@f.GetLastModified()</td>
@if (f.IsValid) {
<td>Valid! @f.GetLog()</td>
<td>
@if (Model.SyntaxCheck[f.FileName] != null && Model.SyntaxCheck[f.FileName].Errors != null) {
<ul>
@foreach(var e in Model.SyntaxCheck[f.FileName]?.Errors) {
<li>@e.Line @e.Column @e.Message </li>
}
</ul>
}
</td>
} else {
<td>@f.GetLog()</td>
<td> </td>
}
</tr>
}

View File

@@ -16,6 +16,7 @@ public interface IXMLInteractionService {
public List<IXMLRoot>? GetRootsList();
public void CreateSearchables(XDocument document);
public List<FileModel>? GetManagedFiles();
public Dictionary<string, SyntaxCheckModel>? Test();
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? SearchCollection(string collection, string searchword, IReaderService reader, ILibrary? lib);
public List<(string Index, List<(string Page, string Line, string Preview, string Identifier)> Results)>? GetPreviews(List<(string, List<Marginal>)> places, IReaderService reader, ILibrary lib);
}

View File

@@ -86,11 +86,12 @@ public class XMLInteractionService : IXMLInteractionService {
public void Collect(List<IFileInfo> files) {
if (files == null || !files.Any()) return;
_ValidState = true;
List<FileModel> res = new List<FileModel>();
Dictionary<string, FileList?>? lF = new Dictionary<string, FileList?>();
List<FileModel> fM = new List<FileModel>();
foreach (var f in files) {
var sb = new StringBuilder();
var m = _CreateFileModel(f, null);
res.Add(m);
fM.Add(m);
// 1. Open File for Reading
try {
using (Stream file = f.CreateReadStream()) {
@@ -118,9 +119,8 @@ public class XMLInteractionService : IXMLInteractionService {
// Success! File can be recognized and parsed.
m.Validate();
foreach (var d in docs) {
if (_Loaded == null) _Loaded = new Dictionary<string, FileList?>();
if (!_Loaded.ContainsKey(d.Prefix)) _Loaded.Add(d.Prefix, new FileList(d.XMLRoot));
_Loaded[d.Prefix]!.Add(d);
if (!lF.ContainsKey(d.Prefix)) lF.Add(d.Prefix, new FileList(d.XMLRoot));
lF[d.Prefix]!.Add(d);
}
}
} catch (Exception ex) {
@@ -128,20 +128,26 @@ public class XMLInteractionService : IXMLInteractionService {
continue;
}
}
if(res.Any()) this._ManagedFiles = res;
// Set validity
// Set data
this._ManagedFiles = fM;
this._Loaded = lF;
foreach (var f in _ManagedFiles) {
if (!f.IsValid) _ValidState = false;
if (!f.IsValid) this._ValidState = false;
break;
}
}
// TODO: Speed up this:
public Dictionary<string, SyntaxCheckModel>? Test() {
if (_Loaded == null) return null;
// TODO: Speed up this, move it into a background task:
var sw = new Stopwatch();
sw.Start();
_testService.Test(this);
var res = this._Loaded?.SelectMany(x => x.Value?.GetFileList()?.Select(x => x.File)).Distinct().Select(x => x.FileName);
var ret = _testService.Test(this._Loaded, res.ToDictionary(x => x, y => new SyntaxCheckModel(y)));
sw.Stop();
Console.WriteLine("Syntaxcheck " + sw.ElapsedMilliseconds.ToString() + " ms");
return ret;
}
public XElement? TryCreate() {

View File

@@ -1,3 +1,4 @@
using HaWeb.Models;
using HaWeb.XMLParser;
namespace HaWeb.XMLTests;
@@ -7,5 +8,5 @@ public interface IXMLTestService {
public Dictionary<string, INodeRule>? Ruleset { get; }
public Dictionary<string, ICollectionRule>? CollectionRuleset { get; }
public void Test(IXMLInteractionService _XMLService);
public Dictionary<string, SyntaxCheckModel>? Test(Dictionary<string, FileList?>? _LoadedFiles, Dictionary<string, SyntaxCheckModel> _Results);
}

View File

@@ -1,4 +1,6 @@
namespace HaWeb.XMLTests;
using HaWeb.Models;
using HaWeb.XMLParser;
public class XMLTestService : IXMLTestService {
@@ -7,28 +9,26 @@ public class XMLTestService : IXMLTestService {
public XMLTestService() {
var roottypes = _GetAllTypesThatImplementInterface<INodeRule>().ToList();
roottypes.ForEach( x => {
if (this.Ruleset == null) this.Ruleset = new Dictionary<string, INodeRule>();
if (this.Ruleset == null) this.Ruleset = new();
var instance = (INodeRule)Activator.CreateInstance(x)!;
if (instance != null) this.Ruleset.Add(instance.Name, instance);
});
var collectionruleset = _GetAllTypesThatImplementInterface<ICollectionRule>().ToList();
collectionruleset.ForEach( x => {
if (this.CollectionRuleset == null) this.CollectionRuleset = new Dictionary<string, ICollectionRule>();
if (this.CollectionRuleset == null) this.CollectionRuleset = new();
var instance = (ICollectionRule)Activator.CreateInstance(x)!;
if (instance != null) this.CollectionRuleset.Add(instance.Name, instance);
});
}
public void Test(IXMLInteractionService _XMLService) {
var docs = _XMLService.GetLoaded();
if (docs == null) return;
var tester = new XMLTester(this, docs);
tester.Test();
public Dictionary<string, SyntaxCheckModel>? Test(Dictionary<string, FileList?>? _Loaded, Dictionary<string, SyntaxCheckModel> _Results) {
if (_Loaded == null) return null;
var tester = new XMLTester(this, _Loaded, _Results);
return tester.Test();
}
private IEnumerable<Type> _GetAllTypesThatImplementInterface<T>()
{
private IEnumerable<Type> _GetAllTypesThatImplementInterface<T>() {
return System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);

View File

@@ -9,12 +9,14 @@ public class XMLTester {
private Dictionary<string, INodeRule>? _Ruleset;
private Dictionary<string, ICollectionRule>? _CollectionRuleset;
private List<XMLRootDocument>? _Documents;
private Dictionary<string, SyntaxCheckModel> _Results;
private Dictionary<string, HashSet<string>>? _IDs;
private Dictionary<string, HashSet<string>>? _CollectionIDs;
private Dictionary<string, List<(XElement, XMLRootDocument)>?> _XPathEvaluated;
public XMLTester (IXMLTestService testService, Dictionary<string, Models.FileList?>? filelists) {
public XMLTester (IXMLTestService testService, Dictionary<string, Models.FileList?>? filelists, Dictionary<string, SyntaxCheckModel> results) {
_Ruleset = testService.Ruleset;
_CollectionRuleset = testService.CollectionRuleset;
_Results = results;
if (filelists != null) {
foreach (var fl in filelists) {
if (fl.Value != null) {
@@ -27,20 +29,21 @@ public class XMLTester {
_XPathEvaluated = new Dictionary<string, List<(XElement, XMLRootDocument)>?>();
}
public void Test() {
if (_Ruleset == null) return;
public Dictionary<string, SyntaxCheckModel>? Test() {
if (_Ruleset == null) return null;
_IDs = new Dictionary<string, HashSet<string>>();
foreach (var rule in _Ruleset) {
buildIDs(rule.Value);
checkRequiredAttributes(rule.Value);
checkReferences(rule.Value);
}
if (_CollectionRuleset == null) return;
if (_CollectionRuleset == null) return null;
_CollectionIDs = new Dictionary<string, HashSet<string>>();
foreach (var collectionrule in _CollectionRuleset) {
buildIDs(collectionrule.Value);
checkReferences(collectionrule.Value);
}
return _Results;
}
private void checkReferences(INodeRule rule) {
@@ -54,7 +57,8 @@ public class XMLTester {
if (_IDs != null && _IDs.ContainsKey(keyname) && hasattr) {
var val = e.Item1.Attribute(r.LinkAttribute)!.Value;
if (!_IDs[keyname].Contains(val)) {
e.Item2.File.Log(generateLogMessage(e.Item1) + "Verlinktes Element " + val + " nicht gefunden.");
var lc = getLineColumn(e.Item1);
_Results[e.Item2.File.FileName].Log(lc.Item1, lc.Item2, "Verlinktes Element " + val + " nicht gefunden.");
}
}
}
@@ -69,7 +73,8 @@ public class XMLTester {
if (elemens != null && elemens.Any()) {
foreach(var r in rule.GenerateBacklinkString(elemens)) {
if (!r.Item4 && !_CollectionIDs[rule.Name].Contains(r.Item1)) {
r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
var lc = getLineColumn(r.Item2);
_Results[r.Item3.File.FileName].Log(lc.Item1, lc.Item2, "Verlinktes Element " + r.Item1 + " nicht gefunden.");
}
if (r.Item4) {
var coll = _CollectionIDs[rule.Name];
@@ -77,15 +82,18 @@ public class XMLTester {
var searchterm = items[0];
var found = coll.Where(x => x.StartsWith(searchterm));
if (items[0] == "NA" || found == null || !found.Any()) {
r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
var lc = getLineColumn(r.Item2);
_Results[r.Item3.File.FileName].Log(lc.Item1, lc.Item2, "Verlinktes Element " + r.Item1 + " nicht gefunden.");
} else {
for (var i = 1; i < items.Length; i++) {
if (items[i] == "NA") break;
else {
searchterm = searchterm + "-" + items[i];
found = found.Where(x => x.StartsWith(searchterm));
if (found == null || !found.Any())
r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
if (found == null || !found.Any()) {
var lc = getLineColumn(r.Item2);
_Results[r.Item3.File.FileName].Log(lc.Item1, lc.Item2, "Verlinktes Element " + r.Item1 + " nicht gefunden.");
}
}
}
}
@@ -126,7 +134,8 @@ public class XMLTester {
if (elemens != null && elemens.Any()) {
foreach (var r in rule.GenerateIdentificationStrings(elemens)) {
if (!hs.Add(r.Item1)) {
r.Item3.File.Log(generateLogMessage(r.Item2) + "Brief-Seite-Zeile " + r.Item1 + " mehrdeutig.");
var lc = getLineColumn(r.Item2);
_Results[r.Item3.File.FileName].Log(lc.Item1, lc.Item2, "Brief-Seite-Zeile " + r.Item1 + " mehrdeutig.");
}
}
}
@@ -143,7 +152,8 @@ public class XMLTester {
foreach (var e in elements) {
if (checkAttribute(e.Item1, attribute, e.Item2)) {
if (!hs.Add(e.Item1.Attribute(attribute)!.Value)) {
e.Item2.File.Log(generateLogMessage(e.Item1) + "Attributwert " + e.Item1.Attribute(attribute)!.Value + " doppelt.");
var lc = getLineColumn(e.Item1);
_Results[e.Item2.File.FileName].Log(lc.Item1, lc.Item2, "Attributwert " + e.Item1.Attribute(attribute)!.Value + " doppelt.");
}
}
}
@@ -152,18 +162,17 @@ public class XMLTester {
private bool checkAttribute(XElement element, string attributename, XMLRootDocument doc, bool log = true) {
if (!element.HasAttributes || element.Attribute(attributename) == null) {
if (log) doc.File.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt.");
if (log) {
var lc = getLineColumn(element);
_Results[doc.File.FileName].Log(lc.Item1, lc.Item2,"Attribut " + attributename + " fehlt.");
};
return false;
}
return true;
}
private string generateLogMessage(XElement element) {
return "Zeile " +
((IXmlLineInfo)element).LineNumber.ToString() +
", Element " +
element.Name +
": ";
private (int, int) getLineColumn(XElement element) {
return (((IXmlLineInfo)element).LineNumber, ((IXmlLineInfo)element).LinePosition);
}
// Cache for XPATH evaluation