Use same yaml structure as cling-tidy

This commit is contained in:
jspijker 2022-11-21 10:51:08 +01:00
parent 2b90807326
commit 4b455d45e9
8 changed files with 85 additions and 124 deletions

View file

@ -10,7 +10,7 @@ dependencies = [
] ]
[project.scripts] [project.scripts]
printer-linter = "printerlinter.terminal:main" printer-linter = "terminal:main"
[build-system] [build-system]
requires = ["setuptools"] requires = ["setuptools"]

View file

@ -1,20 +1,7 @@
from .defintion import Definition from .defintion import Definition
from .diagnostic import Diagnostic from .diagnostic import Diagnostic
from .factory import create
from .meshes import Meshes from .meshes import Meshes
from .profile import Profile from .profile import Profile
__all__ = ["Profile", "Definition", "Meshes", "Diagnostic", "create"] __all__ = ["Profile", "Definition", "Meshes", "Diagnostic", "create"]
def create(file, settings):
if not file.exists():
return None
if ".inst" in file.suffixes and ".cfg" in file.suffixes:
return Profile(file, settings)
if ".def" in file.suffixes and ".json" in file.suffixes:
if file.stem in ("fdmprinter.def", "fdmextruder.def"):
return None
return Definition(file, settings)
if file.parent.stem == "meshes":
return Meshes(file, settings)
return None

View file

@ -1,7 +1,9 @@
import json import json
import re
from pathlib import Path from pathlib import Path
from .diagnostic import Diagnostic from .diagnostic import Diagnostic
from .replacement import Replacement
class Definition: class Definition:
@ -11,6 +13,8 @@ class Definition:
self._defs = {} self._defs = {}
self._getDefs(file) self._getDefs(file)
self._content = self._file.read_text()
settings = {} settings = {}
for k, v in self._defs["fdmprinter"]["settings"].items(): for k, v in self._defs["fdmprinter"]["settings"].items():
self._getSetting(k, v, settings) self._getSetting(k, v, settings)
@ -32,24 +36,25 @@ class Definition:
definition_name = list(self._defs.keys())[0] definition_name = list(self._defs.keys())[0]
definition = self._defs[definition_name] definition = self._defs[definition_name]
if "overrides" in definition and definition_name != "fdmprinter": if "overrides" in definition and definition_name != "fdmprinter":
keys = list(definition["overrides"].keys())
for key, value_dict in definition["overrides"].items(): for key, value_dict in definition["overrides"].items():
is_redefined, value, parent = self._isDefinedInParent(key, value_dict, definition['inherits']) is_redefined, value, parent = self._isDefinedInParent(key, value_dict, definition['inherits'])
if is_redefined: if is_redefined:
termination_key = keys.index(key) + 1 redefined = re.compile(r'.*(\"' + key + r'\"[\s\S]*?\{)[\s\S]*?(\}[,\"]?)')
if termination_key >= len(keys): found = redefined.search(self._content)
# FIXME: find the correct end sequence for now assume it is on the same line yield Diagnostic(
termination_seq = None file = self._file,
else: diagnostic_name = "diagnostic-definition-redundant-override",
termination_seq = keys[termination_key] message = f"Overriding **{key}** with the same value (**{value}**) as defined in parent definition: **{definition['inherits']}**",
yield Diagnostic("diagnostic-definition-redundant-override", level = "Warning",
f"Overriding **{key}** with the same value (**{value}**) as defined in parent definition: **{definition['inherits']}**", offset = found.span(0)[0],
self._file, replacements = [Replacement(
key, file = self._file,
termination_seq) offset = found.span(1)[0],
length = found.span(2)[1] - found.span(1)[0],
replacement_text = "")]
)
def checkValueOutOfBounds(self): def checkValueOutOfBounds(self):
pass pass
def _getSetting(self, name, setting, settings): def _getSetting(self, name, setting, settings):

View file

@ -1,85 +1,20 @@
class Diagnostic: class Diagnostic:
def __init__(self, illness, msg, file, key=None, termination_seq=None): def __init__(self, file, diagnostic_name, message, level, offset, replacements=None):
self.illness = illness
self.key = key
self.msg = msg
self.file = file self.file = file
self._lines = None self.diagnostic_name = diagnostic_name
self._location = None self.message = message
self._fix = None self.offset = offset
self._content_block = None self.level = level
self._termination_seq = termination_seq self.replacements = replacements
@property
def location(self):
if self._location:
return self._location
if not self._lines:
with open(self.file, "r") as f:
if not self.is_text_file:
self._fix = ""
return self._fix
self._lines = f.readlines()
start_location = {"col": 1, "line": 1}
end_location = {"col": len(self._lines[-1]) + 1, "line": len(self._lines) + 1}
if self.key is not None:
for lino, line in enumerate(self._lines, 1):
if f'"{self.key}":' in line:
col = line.index(f'"{self.key}":') + 1
start_location = {"col": col, "line": lino}
if self._termination_seq is None:
end_location = {"col": len(line) + 1, "line": lino}
break
if f'"{self._termination_seq}":' in line:
col = line.index(f'"{self._termination_seq}":') + 1
end_location = {"col": col, "line": lino}
self._location = {"start": start_location, "end": end_location}
return self._location
@property
def is_text_file(self):
return self.file.name.split(".", maxsplit=1)[-1] in ("def.json", "inst.cfg")
@property
def content_block(self):
if self._content_block:
return self._content_block
if not self._lines:
if not self.is_text_file:
self._fix = ""
return self._fix
with open(self.file, "r") as f:
self._lines = f.readlines()
start_line = self.location["start"]["line"] - 1
end_line = self.location["end"]["line"] - 1
self._content_block = "\n".join(self._lines[start_line:end_line])
return self._content_block
@property
def fix(self):
if self._fix:
return self._fix
if not self._lines:
if not self.is_text_file:
self._fix = ""
return self._fix
with open(self.file, "r") as f:
self._lines = f.readlines()
start_line = self.location["start"]["line"] - 2
start_col = 0
end_line = self.location["end"]["line"] - 1
end_col = len(self._lines[start_line:end_line - 1]) + self.location["start"]["col"] - 4 # TODO: double check if 4 holds in all instances
self._fix = self.content_block[start_col:end_col]
return self._fix
def toDict(self): def toDict(self):
diagnostic_dict = {"diagnostic": self.illness, "message": self.msg} diagnostic_dict = {"DiagnosticName": self.diagnostic_name,
if self.is_text_file: "DiagnosticMessage": {
diagnostic_dict |= {"fix": self.fix, "lino": self.location, "content": self.content_block} "Message": self.message,
"FilePath": self.file.as_posix(),
"FileOffset": self.offset,
"Replacements": [] if self.replacements is None else [r.toDict() for r in self.replacements],
},
"Level": self.level
}
return diagnostic_dict return diagnostic_dict

View file

@ -0,0 +1,17 @@
from .profile import Profile
from .defintion import Definition
from .meshes import Meshes
def create(file, settings):
if not file.exists():
return None
if ".inst" in file.suffixes and ".cfg" in file.suffixes:
return Profile(file, settings)
if ".def" in file.suffixes and ".json" in file.suffixes:
if file.stem in ("fdmprinter.def", "fdmextruder.def"):
return None
return Definition(file, settings)
if file.parent.stem == "meshes":
return Meshes(file, settings)
return None

View file

@ -20,15 +20,22 @@ class Meshes:
def checkFileFormat(self): def checkFileFormat(self):
if self._file.suffix.lower() not in (".3mf", ".obj", ".stl"): if self._file.suffix.lower() not in (".3mf", ".obj", ".stl"):
yield Diagnostic("diagnostic-mesh-file-extension", yield Diagnostic(
f"Extension **{self._file.suffix}** not supported, use **3mf**, **obj** or **stl**", file = self._file,
self._file) diagnostic_name = "diagnostic-mesh-file-extension",
message = f"Extension **{self._file.suffix}** not supported, use **3mf**, **obj** or **stl**",
level = "Error"
)
yield yield
def checkFileSize(self): def checkFileSize(self):
if self._file.stat().st_size > self._max_file_size: if self._file.stat().st_size > self._max_file_size:
yield Diagnostic("diagnostic-mesh-file-size", yield Diagnostic(
f"Mesh file with a size **{self._file.stat().st_size}** is bigger then allowed maximum of **{self._max_file_size}**", file = self._file,
self._file) diagnostic_name = "diagnostic-mesh-file-size",
message = f"Mesh file with a size **{self._file.stat().st_size}** is bigger then allowed maximum of **{self._max_file_size}**",
level = "Error",
offset = 0
)
yield yield

View file

@ -0,0 +1,12 @@
class Replacement:
def __init__(self, file, offset, length, replacement_text):
self.file = file
self.offset = offset
self.length = length
self.replacement_text = replacement_text
def toDict(self):
return {"FilePath": self.file.as_posix(),
"Offset": self.offset,
"Length": self.length,
"ReplacementText": self.replacement_text}

View file

@ -8,22 +8,20 @@ from pathlib import Path
import yaml import yaml
from . import create from printerlinter import factory
def examineFile(file, settings): def examineFile(file, settings):
patient = create(file, settings) patient = factory.create(file, settings)
if patient is None: if patient is None:
return {} return {}
full_body_check = {f"{file.as_posix()}": []} body_check = []
for diagnostic in patient.check(): for diagnostic in patient.check():
if diagnostic: if diagnostic:
full_body_check[f"{file.as_posix()}"].append(diagnostic.toDict()) body_check.append(diagnostic.toDict())
if len(full_body_check[f"{file.as_posix()}"]) == 0: return body_check
del full_body_check[f"{file.as_posix()}"]
return full_body_check
def fixFile(file, settings, full_body_check): def fixFile(file, settings, full_body_check):
@ -101,13 +99,13 @@ def main():
settings = yaml.load(f, yaml.FullLoader) settings = yaml.load(f, yaml.FullLoader)
if to_fix or to_diagnose: if to_fix or to_diagnose:
full_body_check = {} full_body_check = {"Diagnostics": []}
for file in files: for file in files:
if file.is_dir(): if file.is_dir():
for fp in file.rglob("**/*"): for fp in file.rglob("**/*"):
full_body_check |= examineFile(fp, settings) full_body_check["Diagnostics"].append(examineFile(fp, settings))
else: else:
full_body_check |= examineFile(file, settings) full_body_check["Diagnostics"].append(examineFile(file, settings))
results = yaml.dump(full_body_check, default_flow_style=False, indent=4, width=240) results = yaml.dump(full_body_check, default_flow_style=False, indent=4, width=240)
if report: if report: