paramecio2fm/paramecio2/libraries/db/dbadmin.py

397 lines
12 KiB
Python

#!/usr/bin/env python3
import argparse
import os,traceback
import sys, inspect
import shutil
import re
from datetime import date
from pathlib import Path
from colorama import init, Fore, Back, Style
from importlib import import_module, reload
from paramecio2.libraries.db.webmodel import WebModel
sys.path.insert(0, os.path.realpath('.'))
try:
from settings import config
except:
print('You need a settings directory with a paramecio2 configuration')
sys.exit(1)
def start():
connection=WebModel.connection()
#connection.connect_to_db(WebModel.connections['default'])
parser = argparse.ArgumentParser(description='A tool for create tables in databases using models from Cromosoma')
parser.add_argument('--model', help='Model python path', required=True)
parser.add_argument('--config', help='The config file', required=False)
args = parser.parse_args()
init()
#Import config
config_file='config'
if args.config!=None:
config_file=args.config
try:
config=import_module('settings.'+config_file)
except:
e = sys.exc_info()[0]
v = sys.exc_info()[1]
print(Fore.WHITE+Back.RED+Style.BRIGHT+"Config file not found: %s %s" % (e, v))
exit(1)
#print(WebModel.connections)
if '/' in args.model:
args.model=args.model.replace('/', '.')[:-3] #.replace('.py', '')
try:
model=import_module(args.model)
for name, obj in inspect.getmembers(sys.modules[model.__name__]):
if inspect.isclass(obj):
if obj.__module__==args.model and hasattr(obj, 'webmodel'):
WebModel.model[name.lower()]=obj(connection)
#WebModel.modelobj
except:
"""
e = sys.exc_info()[0]
v = sys.exc_info()[1]
print(Fore.WHITE+Back.RED+Style.BRIGHT +"Error, file with model not found: %s %s" % (e, v))
"""
print("Exception in user code:")
print("-"*60)
traceback.print_exc(file=sys.stdout)
print("-"*60)
exit(1)
#load the table of databases
cursor=connection.query("show tables")
table_exists=[]
for row in cursor:
table=list(row.values())[0]
if table in WebModel.model:
table_exists.append(table)
#If don't want order
#set([1,2,3,4]) - set([2,5])
tables=list(WebModel.model.keys())
#Array diff ordered
new_tables=[x for x in tables if x not in table_exists]
#If don't want order
#new_tables=set(tables)-set(table_exists)
#Need order new_tables
changes=0
#Create new tables
if len(new_tables)>0:
print(Style.BRIGHT+"Creating new tables...")
changes+=1
for table in new_tables:
print(Style.NORMAL+"--Creating table "+table+"...")
connection.query(WebModel.model[table].create_table())
for table in new_tables:
print("--Adding indexes and constraints for the new table "+table)
for k_field, index in WebModel.arr_sql_index[table].items():
print("---Added index to "+k_field)
connection.query(index)
for k_set, index_set in WebModel.arr_sql_set_index[table].items():
if index_set!="":
connection.query(index_set)
print("---Added constraint to "+k_set)
print("--Adding uniques elements for the new table")
for k_field, unique_set in WebModel.arr_sql_unique[table].items():
if unique_set!="":
connection.query(unique_set)
print("---Added unique to "+unique_set)
#See if changes exists
#Check if created tables are modified.
try:
model_old=import_module('backups.'+args.model)
for name, obj in inspect.getmembers(sys.modules[model_old.__name__]):
if inspect.isclass(obj):
if obj.__module__=='backups.'+args.model and hasattr(obj, 'webmodel'):
WebModel.model['old_'+name.lower()]=obj(connection)
print(Style.BRIGHT+"Checking old versions of model for find changes...")
for table in tables:
#connection.query("")
#Check if new table
#fields_to_add, fields_to_modify, fields_to_add_index, fields_to_add_constraint, fields_to_add_unique, fields_to_delete_index, fields_to_delete_unique, fields_to_delete_constraint, fields_to_delete
fields_to_add=[]
fields_to_modify=[]
fields_to_add_index=[]
fields_to_add_constraint=[]
fields_to_add_unique=[]
fields_to_delete_index=[]
fields_to_delete_unique=[]
fields_to_delete_constraint=[]
fields_to_delete=[]
old_table='old_'+table
if not old_table in WebModel.model:
WebModel.model[old_table]=WebModel.model[table]
for f, v in WebModel.model[table].fields.items():
if not f in WebModel.model[old_table].fields:
fields_to_add.append(f)
#Add index
if v.indexed==True:
fields_to_add_index.append(f)
changes+=1
#Add unique
if v.unique==True:
fields_to_add_unique.append(f)
changes+=1
#Add constraint
if v.foreignkey==True:
fields_to_add_constraint.append(f)
changes+=1
changes+=1
#If exists field in old webmodel and new
else:
v_old=WebModel.model[old_table].fields[f]
if v.get_type_sql()!=v_old.get_type_sql():
fields_to_modify.append(f)
changes+=1
#Add index
if v.indexed==True and v_old.indexed==False:
fields_to_add_index.append(f)
changes+=1
if v.indexed==False and v_old.indexed==True:
fields_to_delete_index.append(f)
changes+=1
#Add unique
if v.unique==True and v_old.unique==False:
fields_to_add_unique.append(f)
changes+=1
if v.unique==False and v_old.unique==True:
fields_to_delete_unique.append(f)
changes+=1
#Add constraint
if v.foreignkey==True and v_old.foreignkey==False:
fields_to_add_constraint.append(f)
changes+=1
if v.foreignkey==False and v_old.foreignkey==True:
fields_to_delete_constraint.append(f)
changes+=1
for f, v in WebModel.model[old_table].fields.items():
if not f in WebModel.model[table].fields:
#Add constraint
if v.foreignkey==True:
fields_to_delete_constraint.append(f)
changes+=1
fields_to_delete.append(f)
changes+=1
WebModel.model[table].update_table(fields_to_add, fields_to_modify, fields_to_add_index, fields_to_add_constraint, fields_to_add_unique, fields_to_delete_index, fields_to_delete_unique, fields_to_delete_constraint, fields_to_delete)
#for field_update in arr_update:
#Make a for in fields, if the field not exist in old model, create, if is not same type, recreate. If no have index now, delete index, if is a new index, create, same thing with uniques
#for field in WebModel.model
except ImportError:
pass
except:
print("Exception in user code:")
print("-"*60)
traceback.print_exc(file=sys.stdout)
print("-"*60)
exit(1)
original_file_path=args.model.replace('.', '/')+'.py'
backup_path='backups/'+original_file_path
if changes>0:
print(Style.BRIGHT+"Creating backup of the model. WARNING: DON'T DELETE BACKUPS DIRECTORY IF YOU WANT MAKE CHANGES IN THE FUTURE WITHOUT MODIFY DIRECTLY THE DATABASE")
create_backup(original_file_path, backup_path)
else:
if not os.path.isfile(backup_path):
create_backup(original_file_path, backup_path)
# Execute script
arr_script_model=args.model.split('.')
arr_script_model.pop()
script_model='.'.join(arr_script_model)+'.scripts.install'
script_py=script_model.replace('.', '/')+'.py'
if os.path.isfile(script_py):
locked_file='/'.join(arr_script_model)+'/scripts/locked'
if not os.path.isfile(locked_file):
script_install=import_module(script_model)
script_install.run()
f=open(locked_file, 'w')
f.write('OK')
f.close()
connection.close()
#script_model=args.model+''
print(Style.BRIGHT+"All tasks finished")
def create_backup(original_file_path, file_path):
#Create copy
path=os.path.dirname(file_path)
p=Path(path)
if not p.is_dir():
p.mkdir(0o755, True)
with open(path+'/__init__.py', 'w') as f:
f.write("#!/usr/bin/env python3\n")
#Create path
if os.path.isfile(file_path):
today = date.today()
shutil.copy(file_path, file_path+'.'+today.strftime("%Y%M%d%H%M%S"))
new_file=""
f=open(original_file_path)
for line in f:
"""
new_line=line.replace("model[\"", "model[\"old_")
new_line=new_line.replace("model['", "model['old_")
new_line=new_line.replace("WebModel(\"", "WebModel(\"old_")
new_line=new_line.replace("WebModel('", "WebModel('old_")
"""
new_file+=line
f.close()
f=open(file_path, 'w')
f.write(new_file)
f.close()