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