olivier.massot 7 年 前
コミット
aea630cc6f
2 ファイル変更80 行追加59 行削除
  1. 79 58
      core.py
  2. 1 1
      qt_viewer.ui

+ 79 - 58
core.py

@@ -1,5 +1,6 @@
 '''
 
+
 @author: olivier.massot
 '''
 import re
@@ -16,14 +17,7 @@ objects = []
 
 # NB: une requete et une table ne peuvent pas porter le même nom.
 
-RXS = {}
-def getrx(nom):
-    try:
-        return RXS[nom]
-    except KeyError:
-        rx = re.compile(r"(?:^|\W)({})(?:$|\W)".format(nom))
-        RXS[nom] = rx
-        return rx
+
 
 def recurse(acc_obj):
     deptree = []
@@ -33,21 +27,39 @@ def recurse(acc_obj):
             deptree += recurse(dep)
     return deptree
 
+class InvalidFileExt(IOError):
+    pass
+
+
 class AccessObject():
     type_ = "<unknown>"
-    def __init__(self, nom, sourcefile):
+    _valid_file_exts = (".bas")
+    def __init__(self, nom):
         self.nom = nom
         self.functions = []
-        self.sourcefile = sourcefile
+        self.sourcefile = ""
         self.deps = []
         self.refs = []
+        self._sourcecode = ""
 
     def __repr__(self):
         return "<{}: {}>".format(self.type_, self.nom)
 
     @classmethod
     def from_file(cls, file):
-        return cls(AccessObject.path_to_name(file), file)
+        file = Path(file)
+        if file.ext not in cls._valid_file_exts:
+            raise InvalidFileExt("Format de fichier d'entée non valide ({})".format(file.name))
+        obj = cls(AccessObject.path_to_name(file))
+        obj.sourcefile = file
+        obj._sourcecode = file.text()
+        return obj
+
+    @property
+    def sourcecode(self):
+        if not self._sourcecode:
+            self._sourcecode = self.sourcefile.text()
+        return self._sourcecode
 
     def add_dep(self, obj):
         if not obj in self.deps:
@@ -67,6 +79,7 @@ class AccessObject():
 
 class TableObject(AccessObject):
     type_ = "Table"
+    _valid_file_exts = (".xml", ".lnkd")
 
 class QueryObject(AccessObject):
     type_ = "Query"
@@ -83,8 +96,16 @@ class MacroObject(AccessObject):
 class ModuleObject(AccessObject):
     type_ = "Module"
 
+    @classmethod
+    def from_file(cls, file):
+        obj = super(ModuleObject, cls).from_file(file)
+        rx = re.compile(r"Sub|Function ([^(]+)\(")
+        obj.functions = [fname for fname in rx.findall(file.text()) if fname]
+        return obj
+
 class RelationObject(AccessObject):
     type_ = "Relation"
+    _valid_file_exts = (".txt")
 
 REFS_ONLY = 1
 DEPS_ONLY = 2
@@ -108,6 +129,19 @@ class Analyse():
             cls.duplicated_names.append(obj.nom)
         cls.objects.append(obj)
 
+    @staticmethod
+    def containsRefsTo(source, target):
+
+        if type(target) is ModuleObject:  # L'objet peut contenir des references aux fonctions de l'objet module
+            for fname in target.functions:
+                rx = re.compile(r"(?:^|\W)({})(?:$|\W)".format(fname))
+                if rx.search(source.sourcecode):
+                    return True
+        else:
+            rx = re.compile(r"(?:^|\W)({})(?:$|\W)".format(target.nom))
+            return rx.search(source.sourcecode)
+
+
     @classmethod
     def run(cls, source_dir, mode=DEPS_AND_REFS):
         source_dir = Path(source_dir)
@@ -118,60 +152,47 @@ class Analyse():
         # Liste les objets à partir de l'arborescence du repertoire des sources
         cls.report(0, 100, "Analyse du répertoire")
 
-        for file in Path(source_dir / "forms").files("*.bas"):
-            obj = FormObject.from_file(file)
-            cls.register(obj)
-
-        for file in Path(source_dir / "reports").files("*.bas"):
-            obj = ReportObject.from_file(file)
-            cls.register(obj)
-
-        for file in Path(source_dir / "relations").files("*.bas"):
-            obj = RelationObject.from_file(file)
-            cls.register(obj)
-
-        for file in Path(source_dir / "scripts").files("*.bas"):
-            obj = MacroObject.from_file(file)
-            cls.register(obj)
-
-        for file in Path(source_dir / "queries").files("*.bas"):
-            obj = QueryObject.from_file(file)
-            cls.register(obj)
-
-        for file in Path(source_dir / "tables").files("*.xml") + Path(source_dir / "tables").files("*.lnkd"):
-            obj = TableObject.from_file(file)
-            cls.register(obj)
-
-        rx = re.compile(r"Sub|Function ([^(]+)\(")
-        for file in Path(source_dir / "modules").files("*.bas"):
-            obj = ModuleObject.from_file(file)
-            obj.functions = [fname for fname in rx.findall(file.text()) if fname]
-            cls.register(obj)
+        sourcemap = {
+                    "forms": FormObject,
+                    "reports": ReportObject,
+                    "relations": RelationObject,
+                    "scripts": MacroObject,
+                    "queries": QueryObject,
+                    "tables": TableObject,
+                    "modules": ModuleObject,
+                     }
+
+        for dirname, accobj in sourcemap.items():
+            for file in Path(source_dir / dirname).files():
+                try:
+                    obj = accobj.from_file(file)
+                    cls.register(obj)
+                except InvalidFileExt:
+                    print("Ignored unrecognized file: {}".format(file))
 
         total = len(cls.objects)
         cls.report(0, total, "> {} objets trouvés".format(total))
 
         # met à jour les dependances en listant les noms d'objets mentionnés dans le fichier subject
-        for i, subject in enumerate(cls.objects):
-            cls.report(i, total, "* {}: {}".format(subject.type_, subject.nom))
-
-            source = subject.sourcefile.text()
-            for object_ in cls.objects:
-                if object_ is subject:
-                    continue
-                if getrx(object_.nom).search(source):
+        for index, subject in enumerate(cls.objects):
+
+            cls.report(index, total, "* {}: {}".format(subject.type_, subject.nom))
+
+            for candidate in cls.objects[:index] + cls.objects[index + 1:]:
+
+                if Analyse.containsRefsTo(subject, candidate):
                     if mode in (DEPS_AND_REFS, DEPS_ONLY):
-                        subject.add_dep(object_)
+                        subject.add_dep(candidate)
                     if mode in (DEPS_AND_REFS, REFS_ONLY):
-                        object_.add_ref(subject)
-                    continue
-                for fname in object_.functions:
-                    if getrx(fname).search(source):
-                        if mode in (DEPS_AND_REFS, DEPS_ONLY):
-                            subject.add_dep(object_)
-                        if mode in (DEPS_AND_REFS, REFS_ONLY):
-                            object_.add_ref(subject)
-                        break
+                        candidate.add_ref(subject)
+#
+#                 for fname in candidate.functions:
+#                     if Analyse.lookFor(fname, source):
+#                         if mode in (DEPS_AND_REFS, DEPS_ONLY):
+#                             subject.add_dep(candidate)
+#                         if mode in (DEPS_AND_REFS, REFS_ONLY):
+#                             candidate.add_ref(subject)
+#                         break
 
         cls.report(total, total, "Analyse terminée")
         cls.ended()

+ 1 - 1
qt_viewer.ui

@@ -357,7 +357,7 @@
           </property>
           <property name="icon">
            <iconset>
-            <normaloff>../access_cleaner/enregistrer_16.png</normaloff>../access_cleaner/enregistrer_16.png</iconset>
+            <normaloff>enregistrer_16.png</normaloff>enregistrer_16.png</iconset>
           </property>
          </widget>
         </item>