Browse Source

Use same yaml structure as cling-tidy

jspijker 2 years ago
parent
commit
4b455d45e9

+ 1 - 1
printer-linter/pyproject.toml

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

+ 1 - 14
printer-linter/src/printerlinter/__init__.py

@@ -1,20 +1,7 @@
 from .defintion import Definition
 from .diagnostic import Diagnostic
+from .factory import create
 from .meshes import Meshes
 from .profile import Profile
 
 __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

+ 18 - 13
printer-linter/src/printerlinter/defintion.py

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

+ 15 - 80
printer-linter/src/printerlinter/diagnostic.py

@@ -1,85 +1,20 @@
 class Diagnostic:
-    def __init__(self, illness, msg, file, key=None, termination_seq=None):
-        self.illness = illness
-        self.key = key
-        self.msg = msg
+    def __init__(self, file, diagnostic_name, message, level, offset, replacements=None):
         self.file = file
-        self._lines = None
-        self._location = None
-        self._fix = None
-        self._content_block = None
-        self._termination_seq = termination_seq
-
-    @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
+        self.diagnostic_name = diagnostic_name
+        self.message = message
+        self.offset = offset
+        self.level = level
+        self.replacements = replacements
 
     def toDict(self):
-        diagnostic_dict = {"diagnostic": self.illness, "message": self.msg}
-        if self.is_text_file:
-            diagnostic_dict |= {"fix": self.fix, "lino": self.location, "content": self.content_block}
+        diagnostic_dict = {"DiagnosticName": self.diagnostic_name,
+                           "DiagnosticMessage": {
+                               "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

+ 17 - 0
printer-linter/src/printerlinter/factory.py

@@ -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

+ 13 - 6
printer-linter/src/printerlinter/meshes.py

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

+ 12 - 0
printer-linter/src/printerlinter/replacement.py

@@ -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}

+ 8 - 10
printer-linter/src/printerlinter/terminal.py → printer-linter/src/terminal.py

@@ -8,22 +8,20 @@ from pathlib import Path
 
 import yaml
 
-from . import create
+from printerlinter import factory
 
 
 def examineFile(file, settings):
-    patient = create(file, settings)
+    patient = factory.create(file, settings)
     if patient is None:
         return {}
 
-    full_body_check = {f"{file.as_posix()}": []}
+    body_check = []
     for diagnostic in patient.check():
         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:
-        del full_body_check[f"{file.as_posix()}"]
-    return full_body_check
+    return body_check
 
 
 def fixFile(file, settings, full_body_check):
@@ -101,13 +99,13 @@ def main():
         settings = yaml.load(f, yaml.FullLoader)
 
     if to_fix or to_diagnose:
-        full_body_check = {}
+        full_body_check = {"Diagnostics": []}
         for file in files:
             if file.is_dir():
                 for fp in file.rglob("**/*"):
-                    full_body_check |= examineFile(fp, settings)
+                    full_body_check["Diagnostics"].append(examineFile(fp, settings))
             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)
             if report: