2021-06-02 14:50:41 +02:00
|
|
|
# -*- coding: UTF-8 -*
|
|
|
|
|
|
|
|
|
|
|
|
"""Outil pour migration ScoDoc 7 => ScoDoc 8
|
|
|
|
|
|
|
|
Pour chaque module dans views:
|
|
|
|
- construire la liste des fonctions définies dans ce module:
|
|
|
|
get_module_functions
|
|
|
|
|
|
|
|
Pour chaque module dans views et dans scodoc:
|
|
|
|
- remplacer context.xxx par app.views.M.xxx
|
|
|
|
où M est le module de views définissant xxx
|
|
|
|
Si xxx n'est pas trouvé, erreur !
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
import re
|
|
|
|
from pprint import pprint as pp
|
2021-06-12 22:43:22 +02:00
|
|
|
import os
|
2021-06-02 14:50:41 +02:00
|
|
|
import sys
|
|
|
|
import types
|
2021-06-12 22:43:22 +02:00
|
|
|
import tempfile
|
|
|
|
import shutil
|
2021-06-02 14:50:41 +02:00
|
|
|
import click
|
|
|
|
|
2021-06-12 22:43:22 +02:00
|
|
|
# import flask
|
2021-06-02 14:50:41 +02:00
|
|
|
|
2021-06-12 22:43:22 +02:00
|
|
|
# import app
|
|
|
|
# from app import create_app, cli, db
|
|
|
|
# from app.auth.models import User, Role, UserRole
|
2021-06-02 14:50:41 +02:00
|
|
|
|
2021-06-12 22:43:22 +02:00
|
|
|
# from app.views import notes
|
2021-06-02 14:50:41 +02:00
|
|
|
|
|
|
|
TYPES_TO_SCAN = {
|
|
|
|
types.FunctionType,
|
|
|
|
# types.ClassType,
|
|
|
|
# types.DictionaryType,
|
|
|
|
# types.FloatType,
|
|
|
|
# types.IntType,
|
|
|
|
# types.ListType,
|
|
|
|
# types.StringType,
|
|
|
|
# types.TupleType,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def get_module_symbols(module):
|
|
|
|
"""returns list of symbols (functions and constants) defined in the given module"""
|
|
|
|
return [
|
|
|
|
f.__name__
|
|
|
|
for f in [getattr(module, name) for name in dir(module)]
|
|
|
|
if (type(f) in TYPES_TO_SCAN)
|
|
|
|
and ((type(f) != types.FunctionType) or (f.__module__ == module.__name__))
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# print("\n".join(f.__name__ for f in get_module_functions(notes)))
|
|
|
|
|
|
|
|
|
|
|
|
def scan_views_symbols():
|
|
|
|
"""Scan modules in app.views and returns
|
|
|
|
{ }
|
|
|
|
"""
|
2021-06-12 22:43:22 +02:00
|
|
|
import app
|
|
|
|
|
2021-06-02 14:50:41 +02:00
|
|
|
views_modules = [
|
|
|
|
getattr(app.views, mod_name)
|
|
|
|
for mod_name in dir(app.views)
|
|
|
|
if type(getattr(app.views, mod_name)) == types.ModuleType
|
|
|
|
]
|
|
|
|
sym2mod = {} # symbole_name : module
|
|
|
|
for module in views_modules:
|
|
|
|
start = "app.views."
|
|
|
|
assert module.__name__.startswith(start)
|
|
|
|
module_name = module.__name__[len(start) :]
|
|
|
|
symbols = set(get_module_symbols(module))
|
|
|
|
print("%d symbols defined in %s" % (len(symbols), module))
|
|
|
|
dups = symbols.intersection(sym2mod)
|
|
|
|
if len(dups):
|
|
|
|
print("duplicated symbols !")
|
|
|
|
for dup in dups:
|
|
|
|
print("%s:\t%s\t%s" % (dup, sym2mod[dup], module_name))
|
|
|
|
|
|
|
|
sym2mod.update({s: module_name for s in symbols})
|
|
|
|
return sym2mod
|
|
|
|
|
|
|
|
|
|
|
|
def replace_context_calls(sourcefilename, sym2mod):
|
|
|
|
undefined_list = [] # noms de fonctions non présents dans les modules "views"
|
|
|
|
|
|
|
|
def repl(m):
|
|
|
|
funcname = m.group(1)
|
|
|
|
module = sym2mod.get(funcname, False)
|
|
|
|
if module:
|
|
|
|
return module + "." + funcname
|
|
|
|
else:
|
|
|
|
undefined_list.append((sourcefilename, funcname))
|
|
|
|
return m.group(0) # leave unchanged
|
|
|
|
|
|
|
|
print("reading %s" % sourcefilename)
|
|
|
|
source = open(sourcefilename).read()
|
|
|
|
exp = re.compile(r"context\.([a-zA-Z0-9_]+)")
|
|
|
|
source2 = exp.sub(repl, source)
|
|
|
|
return source2, undefined_list
|
|
|
|
|
|
|
|
|
2021-06-12 22:43:22 +02:00
|
|
|
# sym2mod = scan_views_symbols()
|
|
|
|
|
|
|
|
# source2, undefined_list = replace_context_calls("app/scodoc/sco_core.py", sym2mod)
|
2021-06-02 14:50:41 +02:00
|
|
|
|
2021-06-12 22:43:22 +02:00
|
|
|
|
|
|
|
def list_context_calls(sourcefilename):
|
|
|
|
"""List of methods called on context in this file"""
|
|
|
|
source = open(sourcefilename).read()
|
|
|
|
exp = re.compile(r"context\.([a-zA-Z0-9_]+)")
|
|
|
|
return sorted(set(exp.findall(source)))
|
|
|
|
|
|
|
|
|
|
|
|
@click.group()
|
|
|
|
def cli():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@cli.command()
|
|
|
|
@click.argument("src_filenames", nargs=-1)
|
|
|
|
def showcontextcalls(src_filenames):
|
|
|
|
click.echo("Initialized the database")
|
|
|
|
S = {}
|
|
|
|
for sourcefilename in src_filenames:
|
|
|
|
l = list_context_calls(sourcefilename)
|
|
|
|
module_name = os.path.splitext(os.path.split(sourcefilename)[1])[0]
|
|
|
|
for m in l:
|
|
|
|
if m in S:
|
|
|
|
S[m].append(module_name)
|
|
|
|
else:
|
|
|
|
S[m] = [module_name]
|
|
|
|
#
|
|
|
|
for method in sorted(S.keys()):
|
|
|
|
print(method + ":\t" + ", ".join(S[method]))
|
|
|
|
|
|
|
|
|
|
|
|
@cli.command()
|
|
|
|
@click.argument("method", nargs=1)
|
|
|
|
@click.argument("module", nargs=1)
|
|
|
|
@click.argument("src_filenames", nargs=-1)
|
|
|
|
def refactor(method, module, src_filenames):
|
|
|
|
"""Replace call context.method
|
|
|
|
by module.method
|
|
|
|
in all given source filenames
|
|
|
|
"""
|
|
|
|
backup = tempfile.mkdtemp(dir="/tmp")
|
|
|
|
for sourcefilename in src_filenames:
|
|
|
|
print("reading %s" % sourcefilename)
|
|
|
|
source = open(sourcefilename).read()
|
|
|
|
source2 = source.replace("context." + method, module + "." + method)
|
|
|
|
shutil.move(sourcefilename, backup)
|
|
|
|
open(sourcefilename, "w").write(source2)
|
|
|
|
print("Done.\noriginal files saved in %s\n" % backup)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
try:
|
|
|
|
cli(obj={})
|
|
|
|
except SystemExit as e:
|
|
|
|
if e.code != 0:
|
|
|
|
raise
|