This commit is contained in:
long2ice
2020-05-13 23:16:27 +08:00
parent a5a5de529b
commit d385647fba
9 changed files with 185 additions and 122 deletions

View File

@@ -3,8 +3,13 @@ import os
import sys
from enum import Enum
import click
from click import BadParameter, ClickException
import asyncclick as click
from asyncclick import BadParameter, ClickException
from tortoise import Tortoise, generate_schema_for_client
from alice.backends.mysql import MysqlDDL
from alice.migrate import Migrate
from alice.utils import get_app_connection
sys.path.append(os.getcwd())
@@ -15,15 +20,15 @@ class Color(str, Enum):
@click.group(context_settings={'help_option_names': ['-h', '--help']})
@click.option('-c', '--config', default='settings',
@click.option('-c', '--config', default='settings', show_default=True,
help='Tortoise-ORM config module, will read config variable from it, default is `settings`.')
@click.option('-t', '--tortoise-orm', default='TORTOISE_ORM',
@click.option('-t', '--tortoise-orm', default='TORTOISE_ORM', show_default=True,
help='Tortoise-ORM config dict variable, default is `TORTOISE_ORM`.')
@click.option('-l', '--location', default='./migrations',
@click.option('-l', '--location', default='./migrations', show_default=True,
help='Migrate store location, default is `./migrations`.')
@click.option('--connection', default='default', help='Tortoise-ORM connection name, default is `default`.')
@click.option('-a', '--app', default='models', show_default=True, help='Tortoise-ORM app name, default is `models`.')
@click.pass_context
def cli(ctx, config, tortoise_orm, location, connection):
async def cli(ctx, config, tortoise_orm, location, app):
ctx.ensure_object(dict)
try:
config_module = importlib.import_module(config)
@@ -31,10 +36,16 @@ def cli(ctx, config, tortoise_orm, location, connection):
if not config:
raise BadParameter(param_hint=['--config'],
message=f'Can\'t get "{tortoise_orm}" from module "{config_module}"')
await Tortoise.init(config=config)
ctx.obj['config'] = config
ctx.obj['location'] = location
if connection not in config.get('connections').keys():
raise BadParameter(param_hint=['--connection'], message=f'No connection found in "{config}"')
ctx.obj['app'] = app
if app not in config.get('apps').keys():
raise BadParameter(param_hint=['--app'], message=f'No app found in "{config}"')
except ModuleNotFoundError:
raise BadParameter(param_hint=['--tortoise-orm'], message=f'No module named "{config}"')
@@ -43,6 +54,17 @@ def cli(ctx, config, tortoise_orm, location, connection):
@click.pass_context
def migrate(ctx):
config = ctx.obj['config']
location = ctx.obj['location']
app = ctx.obj['app']
old_models = Migrate.read_old_models(app, location)
print(old_models)
new_models = Tortoise.apps.get(app)
print(new_models)
ret = Migrate(MysqlDDL(get_app_connection(config, app))).diff_models(old_models, new_models)
print(ret)
@cli.command()
@@ -58,26 +80,38 @@ def downgrade():
@cli.command()
@click.option('--safe', is_flag=True, default=True,
help='When set to true, creates the table only when it does not already exist..', show_default=True)
@click.pass_context
def initdb():
pass
async def initdb(ctx, safe):
location = ctx.obj['location']
config = ctx.obj['config']
app = ctx.obj['app']
await generate_schema_for_client(get_app_connection(config, app), safe)
Migrate.write_old_models(app, location)
click.secho(f'Success initdb for app `{app}`', fg=Color.green)
@cli.command()
@click.option('--overwrite', type=bool, default=False, help='Overwrite old_models.py.')
@click.option('--overwrite', is_flag=True, default=False, help=f'Overwrite {Migrate.old_models}.', show_default=True)
@click.pass_context
def init(ctx, overwrite):
location = ctx.obj['location']
config = ctx.obj['config']
if not os.path.isdir(location) or overwrite:
app = ctx.obj['app']
if not os.path.isdir(location):
os.mkdir(location)
connections = config.get('connections').keys()
for connection in connections:
dirname = os.path.join(location, connection)
if not os.path.isdir(dirname):
os.mkdir(dirname)
click.secho(f'Success create migrate location {dirname}', fg=Color.green)
if overwrite:
pass
dirname = os.path.join(location, app)
if not os.path.isdir(dirname):
os.mkdir(dirname)
click.secho(f'Success create migrate location {dirname}', fg=Color.green)
if overwrite:
Migrate.write_old_models(app, location)
else:
raise ClickException('Already inited')
if __name__ == '__main__':
cli(_anyio_backend='asyncio')

View File

@@ -1,8 +1,12 @@
import importlib
import inspect
import os
from copy import deepcopy
import dill
from typing import List, Type, Dict
from tortoise import Model, ForeignKeyFieldInstance
from tortoise import Model, ForeignKeyFieldInstance, Tortoise
from tortoise.fields import Field
from alice.backends import DDL
@@ -11,11 +15,30 @@ from alice.backends import DDL
class Migrate:
operators: List
ddl: DDL
old_models = 'old_models.pickle'
def __init__(self, ddl: DDL):
self.operators = []
self.ddl = ddl
@staticmethod
def write_old_models(app, location):
ret = Tortoise.apps.get(app)
old_models = {}
for k, v in ret.items():
old_models[k] = deepcopy(v)
dirname = os.path.join(location, app)
with open(os.path.join(dirname, Migrate.old_models), 'wb') as f:
dill.dump(old_models, f, )
@staticmethod
def read_old_models(app, location):
dirname = os.path.join(location, app)
with open(os.path.join(dirname, Migrate.old_models), 'rb') as f:
return dill.load(f, )
def diff_models_module(self, old_models_module, new_models_module):
old_module = importlib.import_module(old_models_module)
old_models = {}

View File

@@ -1,17 +1,11 @@
import re
from tortoise import Tortoise
def cp_models(old_model_file, new_model_file, new_app):
def get_app_connection(config: dict, app: str):
"""
cp models file to old_models.py and rename model app
:param old_app:
:param new_app:
:param old_model_file:
:param new_model_file:
:return:r
get tortoise connection by app
:param config:
:param app:
:return:
"""
pattern = r'(ManyToManyField|ForeignKeyField|OneToOneField)\((model_name)?(\"|\')(?P<app>\w+).+\)'
with open(old_model_file, 'r') as f:
content = f.read()
ret = re.sub(pattern, rf'{new_app} \g<app>', content)
print(ret)
return Tortoise.get_connection(config.get('apps').get(app).get('default_connection')),