|
|
@@ -9,13 +9,12 @@ from path import Path
|
|
|
objects = []
|
|
|
|
|
|
|
|
|
-SUBSTR = {92: "\\", 47: "/", 58: ":", 42: "*", 63:"?", 34:"\"", 60:"<", 62:">", 124:"|" }
|
|
|
-def path_to_name(path):
|
|
|
- name_ = path.name.stripext()
|
|
|
- for ascii_code, char in SUBSTR.items():
|
|
|
- name_ = name_.replace("[{}]".format(ascii_code), char)
|
|
|
- return name_
|
|
|
|
|
|
+# TODO: gérer les cas où des objets de types différents portent le même nom. Ex: une table et un formulaire...
|
|
|
+# TODO: ignorer les commentaires dans le modules
|
|
|
+# TODO: ignorer les labels dans les formulaires et états
|
|
|
+
|
|
|
+# NB: une requete et une table ne peuvent pas porter le même nom.
|
|
|
|
|
|
RXS = {}
|
|
|
def getrx(nom):
|
|
|
@@ -35,9 +34,9 @@ def recurse(acc_obj):
|
|
|
return deptree
|
|
|
|
|
|
class AccessObject():
|
|
|
- def __init__(self, type_, nom, sourcefile):
|
|
|
+ type_ = "<unknown>"
|
|
|
+ def __init__(self, nom, sourcefile):
|
|
|
self.nom = nom
|
|
|
- self.type_ = type_
|
|
|
self.functions = []
|
|
|
self.sourcefile = sourcefile
|
|
|
self.deps = []
|
|
|
@@ -46,6 +45,10 @@ class AccessObject():
|
|
|
def __repr__(self):
|
|
|
return "<{}: {}>".format(self.type_, self.nom)
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def from_file(cls, file):
|
|
|
+ return cls(AccessObject.path_to_name(file), file)
|
|
|
+
|
|
|
def add_dep(self, obj):
|
|
|
if not obj in self.deps:
|
|
|
self.deps.append(obj)
|
|
|
@@ -54,11 +57,42 @@ class AccessObject():
|
|
|
if not obj in self.refs:
|
|
|
self.refs.append(obj)
|
|
|
|
|
|
+ SUBSTR = {92: "\\", 47: "/", 58: ":", 42: "*", 63:"?", 34:"\"", 60:"<", 62:">", 124:"|" }
|
|
|
+ @staticmethod
|
|
|
+ def path_to_name(path):
|
|
|
+ name_ = path.name.stripext()
|
|
|
+ for ascii_code, char in AccessObject.SUBSTR.items():
|
|
|
+ name_ = name_.replace("[{}]".format(ascii_code), char)
|
|
|
+ return name_
|
|
|
+
|
|
|
+class TableObject(AccessObject):
|
|
|
+ type_ = "Table"
|
|
|
+
|
|
|
+class QueryObject(AccessObject):
|
|
|
+ type_ = "Query"
|
|
|
+
|
|
|
+class FormObject(AccessObject):
|
|
|
+ type_ = "Form"
|
|
|
+
|
|
|
+class ReportObject(AccessObject):
|
|
|
+ type_ = "Report"
|
|
|
+
|
|
|
+class MacroObject(AccessObject):
|
|
|
+ type_ = "Macro"
|
|
|
+
|
|
|
+class ModuleObject(AccessObject):
|
|
|
+ type_ = "Module"
|
|
|
+
|
|
|
+class RelationObject(AccessObject):
|
|
|
+ type_ = "Relation"
|
|
|
+
|
|
|
+REFS_ONLY = 1
|
|
|
+DEPS_ONLY = 2
|
|
|
+DEPS_AND_REFS = 3
|
|
|
+
|
|
|
class Analyse():
|
|
|
objects = []
|
|
|
-
|
|
|
- def __enter__(self):
|
|
|
- pass
|
|
|
+ duplicated_names = []
|
|
|
|
|
|
@staticmethod
|
|
|
def report(current, total, msg=""):
|
|
|
@@ -69,49 +103,79 @@ class Analyse():
|
|
|
pass
|
|
|
|
|
|
@classmethod
|
|
|
- def run(cls, source_dir):
|
|
|
+ def register(cls, obj):
|
|
|
+ if obj.nom in [other.nom for other in cls.objects] and not obj.nom in cls.duplicated_names:
|
|
|
+ cls.duplicated_names.append(obj.nom)
|
|
|
+ cls.objects.append(obj)
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def run(cls, source_dir, mode=DEPS_AND_REFS):
|
|
|
source_dir = Path(source_dir)
|
|
|
|
|
|
cls.objects = []
|
|
|
+ cls.duplicated_names = []
|
|
|
|
|
|
# Liste les objets à partir de l'arborescence du repertoire des sources
|
|
|
cls.report(0, 100, "Analyse du répertoire")
|
|
|
|
|
|
- for folder in ["queries", "forms", "relations", "reports", "scripts"]:
|
|
|
- for file in Path(source_dir / folder).files("*.bas"):
|
|
|
- cls.objects.append(AccessObject(folder, path_to_name(file), file))
|
|
|
+ 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"):
|
|
|
- cls.objects.append(AccessObject("tables", path_to_name(file), file))
|
|
|
+ obj = TableObject.from_file(file)
|
|
|
+ cls.register(obj)
|
|
|
|
|
|
rx = re.compile(r"Sub|Function ([^(]+)\(")
|
|
|
for file in Path(source_dir / "modules").files("*.bas"):
|
|
|
- obj = AccessObject("modules", path_to_name(file), file)
|
|
|
+ obj = ModuleObject.from_file(file)
|
|
|
obj.functions = [fname for fname in rx.findall(file.text()) if fname]
|
|
|
- cls.objects.append(obj)
|
|
|
+ cls.register(obj)
|
|
|
|
|
|
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.nom))
|
|
|
+ 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):
|
|
|
- subject.add_dep(object_)
|
|
|
- object_.add_ref(subject)
|
|
|
+ if mode in (DEPS_AND_REFS, DEPS_ONLY):
|
|
|
+ subject.add_dep(object_)
|
|
|
+ if mode in (DEPS_AND_REFS, REFS_ONLY):
|
|
|
+ object_.add_ref(subject)
|
|
|
continue
|
|
|
for fname in object_.functions:
|
|
|
if getrx(fname).search(source):
|
|
|
- subject.add_dep(object_)
|
|
|
- object_.add_ref(subject)
|
|
|
+ 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
|
|
|
|
|
|
cls.report(total, total, "Analyse terminée")
|
|
|
cls.ended()
|
|
|
+
|
|
|
return cls.objects
|
|
|
|
|
|
|