|
|
@@ -28,11 +28,11 @@ class InvalidFileExt(IOError):
|
|
|
pass
|
|
|
|
|
|
class Mention():
|
|
|
- def __init__(self, line, objname, quote):
|
|
|
+ def __init__(self, line, objname, quote, obj):
|
|
|
self.line = line
|
|
|
self.objname = objname
|
|
|
self.quote = quote
|
|
|
- self.obj = None
|
|
|
+ self.obj = obj
|
|
|
|
|
|
class AccessObject():
|
|
|
type_ = "<unknown>"
|
|
|
@@ -45,7 +45,8 @@ class AccessObject():
|
|
|
self._sourcecode = ""
|
|
|
|
|
|
self.mentions = []
|
|
|
- self.deps = {}
|
|
|
+ self.deps = []
|
|
|
+ self.refs = []
|
|
|
|
|
|
def __repr__(self):
|
|
|
return "<{}: {}>".format(self.type_, self.name_)
|
|
|
@@ -107,7 +108,7 @@ class RelationObject(AccessObject):
|
|
|
|
|
|
class Analyse():
|
|
|
objects = []
|
|
|
- duplicated_names = []
|
|
|
+ index = {}
|
|
|
|
|
|
@classmethod
|
|
|
def report(cls, current, total, msg=""):
|
|
|
@@ -138,22 +139,31 @@ class Analyse():
|
|
|
for file in Path(source_dir / dirname).files():
|
|
|
try:
|
|
|
obj = accobj.from_file(file)
|
|
|
- if obj.name_ in [other.name_ for other in cls.objects] and not obj.name_ in cls.duplicated_names:
|
|
|
- cls.duplicated_names.append(obj.name_)
|
|
|
+
|
|
|
cls.objects.append(obj)
|
|
|
+
|
|
|
+ if type(obj) is not ModuleObject:
|
|
|
+ if not obj.name_ in cls.index:
|
|
|
+ cls.index[obj.name_] = []
|
|
|
+ cls.index[obj.name_].append(obj)
|
|
|
+ else:
|
|
|
+ for fname in obj.functions:
|
|
|
+ if not fname in cls.index:
|
|
|
+ cls.index[fname] = []
|
|
|
+ cls.index[fname].append(obj)
|
|
|
+
|
|
|
except InvalidFileExt:
|
|
|
print("Ignored unrecognized file: {}".format(file))
|
|
|
|
|
|
@classmethod
|
|
|
- def find_deps(cls, subject):
|
|
|
+ def parse_source(cls, subject):
|
|
|
|
|
|
# On cherche le nom de chaque autre objet, ainsi que le nom des fonctions issues des modules
|
|
|
- look_for = [obj.name_ for obj in cls.objects if obj is not subject] + sum([obj.functions for obj in cls.objects if obj is not subject])
|
|
|
+ look_for = [obj.name_ for obj in cls.objects if obj is not subject] + list(sum([obj.functions for obj in cls.objects if obj is not subject], []))
|
|
|
|
|
|
names = "|".join(list(set(look_for)))
|
|
|
|
|
|
rx = re.compile("""(.*(?:^|\t| |\[|\]|&|\(|\)|\.|!|"|')({})(?:$|\t| |\[|\]|&|\(|\)|\.|!|"|').*)""".format(names), MULTILINE)
|
|
|
- mentions = []
|
|
|
|
|
|
# Indexe la position des lignes
|
|
|
line_ends = [m.end() for m in re.finditer('.*\n', subject.sourcecode)]
|
|
|
@@ -162,36 +172,65 @@ class Analyse():
|
|
|
line = next(i for i in range(len(line_ends)) if line_ends[i] > match.start(1)) + 1
|
|
|
quote = match.group(1).strip()
|
|
|
objname = match.group(2)
|
|
|
- mentions.append(Mention(line, objname, quote))
|
|
|
- subject.mentions = mentions
|
|
|
|
|
|
-# if mentions:
|
|
|
-# subject.deps[candidate] = mentions
|
|
|
+ if len(cls.index[objname]) == 1:
|
|
|
+ obj = cls.index[objname][0]
|
|
|
+ else:
|
|
|
+ print("!!! Duplicate")
|
|
|
+
|
|
|
+ subject.mentions.append(Mention(line, objname, quote, obj))
|
|
|
+
|
|
|
|
|
|
@classmethod
|
|
|
- def analyse_all(cls):
|
|
|
+ def parse_all(cls):
|
|
|
# Mise à jour des dépendances:
|
|
|
# # parcourt les objets, et recherche dans le code source de chacun des mentions du nom des autres objets.
|
|
|
+ for index, subject in enumerate(cls.objects):
|
|
|
+ cls.report(index, len(cls.objects), "* {}: {}".format(subject.type_, subject.name_))
|
|
|
+ cls.parse_source(subject)
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def build_trees(cls):
|
|
|
total = len(cls.objects)
|
|
|
for index, subject in enumerate(cls.objects):
|
|
|
- cls.report(index, total, "* {}: {}".format(subject.type_, subject.name_))
|
|
|
- cls.find_deps(subject)
|
|
|
+ cls.report(index, total * 2)
|
|
|
+
|
|
|
+ for mention in subject.mentions:
|
|
|
+ if not mention.obj in subject.deps:
|
|
|
+ subject.deps.append(mention.obj)
|
|
|
+
|
|
|
+ for index, subject in enumerate(cls.objects):
|
|
|
+ cls.report(total + index, total * 2)
|
|
|
+
|
|
|
+ for obj in cls.objects:
|
|
|
+ if obj is subject:
|
|
|
+ continue
|
|
|
+ if subject in obj.deps:
|
|
|
+ subject.refs.append(obj)
|
|
|
|
|
|
@classmethod
|
|
|
def run(cls, source_dir):
|
|
|
# Liste les objets à partir de l'arborescence du repertoire des sources
|
|
|
- cls.report(0, 100, "Analyse du répertoire")
|
|
|
+ cls.report(0, 100, "Chargement des données")
|
|
|
cls.load_objects(source_dir)
|
|
|
|
|
|
cls.report(0, 100, "> {} objets trouvés".format(len(cls.objects)))
|
|
|
+ cls.report(0, 100, "Analyse du code source".format(len(cls.objects)))
|
|
|
+ cls.parse_all()
|
|
|
|
|
|
- cls.analyse_all()
|
|
|
+ cls.report(0, 100, "Construction de l'arbre des dépendances".format(len(cls.objects)))
|
|
|
+ cls.build_trees()
|
|
|
|
|
|
cls.report(100, 100, "Analyse terminée")
|
|
|
cls.ended()
|
|
|
|
|
|
return cls.objects
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def duplicates(cls):
|
|
|
+ return {k: v for k, v in cls.items() if len(v) > 1}
|
|
|
+
|
|
|
+
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
here = Path(__file__).parent.abspath()
|
|
|
@@ -199,24 +238,29 @@ if __name__ == "__main__":
|
|
|
resultfile = here / r"test\analyse.txt"
|
|
|
resultfile.remove_p()
|
|
|
|
|
|
- def print_(i, total, msg):
|
|
|
- print("({}/{}) {}".format(i, total, msg))
|
|
|
+ def print_(i, total, msg=""):
|
|
|
+ if msg:
|
|
|
+ print("({}/{}) {}".format(i, total, msg))
|
|
|
|
|
|
Analyse.report = print_
|
|
|
|
|
|
Analyse.run(source_dir)
|
|
|
|
|
|
- with open(resultfile, "w+") as f:
|
|
|
+ with open(resultfile, "w+", encoding='utf-8') as f:
|
|
|
for obj in Analyse.objects:
|
|
|
- msg = "# L'objet [{}] '{}' mentionne dans son code-source:".format(obj.type_, obj.name_)
|
|
|
- for mention in obj.mentions:
|
|
|
- msg += "\n\t\t'{}'\t\tLine: {}\t>>\t{}".format(mention.objname, mention.line, mention.quote)
|
|
|
-# for dep, mentions in obj.deps.items():
|
|
|
-# msg += "\n\t* [{}] '{}'".format(dep.type_, dep.name_)
|
|
|
-# for mention in mentions:
|
|
|
-# msg += "\n\t\tLine: {} >> {}".format(mention.line, mention.quote)
|
|
|
-# if not obj.deps:
|
|
|
-# msg += "\n\t (pas de dépendances)"
|
|
|
+ msg = "# '{}' [{}]".format(obj.name_, obj.type_)
|
|
|
+ if obj.deps:
|
|
|
+ msg += "\n\tMentionne: {}".format(", ".join(["'{}' [{}]".format(dep.name_, dep.type_) for dep in obj.deps]))
|
|
|
+ else:
|
|
|
+ msg += "\n\t (ne mentionne aucun autre objet)"
|
|
|
+ if obj.refs:
|
|
|
+ msg += "\n\tEst mentionné par: {}".format(", ".join(["'{}' [{}]".format(ref.name_, ref.type_) for ref in obj.refs]))
|
|
|
+ else:
|
|
|
+ msg += "\n\t (n'est mentionné nul part ailleurs)"
|
|
|
+ if obj.mentions:
|
|
|
+ msg += "\n\t Détail:"
|
|
|
+ for mention in obj.mentions:
|
|
|
+ msg += "\n\t\t'{}'\t\tLine: {}\t>>\t{}".format(mention.objname, mention.line, mention.quote)
|
|
|
|
|
|
msg += "\n"
|
|
|
f.write(msg)
|