diff --git a/app/native/wndb/__init__.py b/app/native/wndb/__init__.py index c089b87..8a5978b 100644 --- a/app/native/wndb/__init__.py +++ b/app/native/wndb/__init__.py @@ -14,15 +14,15 @@ # ----------------------------------------------------------------------------- # 项目生命周期与 INP 导入导出 # ----------------------------------------------------------------------------- -from .project_backup import ( +from .project import ( list_project, have_project, create_project, delete_project, clean_project, ) -from .project_backup import is_project_open, open_project, close_project -from .project_backup import copy_project +from .project import is_project_open, open_project, close_project +from .project import copy_project # DingZQ, 2024-12-28: 将 INP v3 转换为 v2 from .inp_in import read_inp, import_inp, convert_inp_v3_to_v2 diff --git a/app/native/wndb/project_backup.py b/app/native/wndb/project_backup.py deleted file mode 100644 index bfe2e83..0000000 --- a/app/native/wndb/project_backup.py +++ /dev/null @@ -1,183 +0,0 @@ -import os -import psycopg as pg -from psycopg import sql -from psycopg.rows import dict_row -from .connection import g_conn_dict as conn -from app.core.config import get_pgconn_string - -# no undo/redo - -_server_databases = ["template0", "template1", "postgres", "project"] - - -def list_project() -> list[str]: - ps = [] - - with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: - with conn.cursor(row_factory=dict_row) as cur: - for p in cur.execute( - f"select datname from pg_database where datname <> 'postgres' and datname <> 'template0' and datname <> 'template1' and datname <> 'project'" - ): - ps.append(p["datname"]) - return ps - - -def have_project(name: str) -> bool: - with pg.connect( - conninfo=get_pgconn_string(db_name="postgres"), autocommit=True - ) as conn: - with conn.cursor() as cur: - cur.execute("select 1 from pg_database where datname = %s", (name,)) - return cur.fetchone() is not None - - -def copy_project(source: str, new: str) -> None: - if source in conn: - conn[source].close() - del conn[source] - - with pg.connect( - conninfo=get_pgconn_string(db_name="postgres"), autocommit=True - ) as admin_conn: - with admin_conn.cursor() as cur: - cur.execute( - "update pg_database set datallowconn = false where datname = %s", - (source,), - ) - try: - cur.execute( - "select pg_terminate_backend(pid) from pg_stat_activity where datname = %s and pid <> pg_backend_pid()", - (source,), - ) - cur.execute( - sql.SQL("create database {} with template = {}").format( - sql.Identifier(new), sql.Identifier(source) - ) - ) - finally: - cur.execute( - "update pg_database set datallowconn = true where datname = %s", - (source,), - ) - - -# 2025-02-07, WMH -# copyproject会把pg中operation这个表的全部内容也加进去,我们实际项目运行一周后operation这个表会变得特别大,导致CopyProject花费的时间很长,CopyProjectEx把operation的在复制时没有一块复制过去,节省时间 -class CopyProjectEx: - @staticmethod - def create_database(connection, new_db): - with connection.cursor() as cursor: - cursor.execute(f'create database "{new_db}"') - connection.commit() - - @staticmethod - def execute_pg_dump(hostname, source_db, exclude_table_list): - dump_command_structure = ( - f"pg_dump -h {hostname} -F c -s -f source_db_structure.dump {source_db}" - ) - os.system(dump_command_structure) - - if exclude_table_list is not None: - exclude_table = " ".join(["-T {}".format(i) for i in exclude_table_list]) - dump_command_db = f"pg_dump -h {hostname} -F c -a {exclude_table} -f source_db.dump {source_db}" - else: - dump_command_db = ( - f"pg_dump -h {hostname} -F c -a -f source_db.dump {source_db}" - ) - os.system(dump_command_db) - - @staticmethod - def execute_pg_restore(hostname, new_db): - restore_command_structure = ( - f"pg_restore -h {hostname} -d {new_db} source_db_structure.dump" - ) - os.system(restore_command_structure) - - restore_command_db = f"pg_restore -h {hostname} -d {new_db} source_db.dump" - os.system(restore_command_db) - - @staticmethod - def init_operation_table(connection, excluded_table): - with connection.cursor() as cursor: - if "operation" in excluded_table: - insert_query = "insert into operation (id, redo, undo, redo_cs, undo_cs) values (0, '', '', '', '')" - cursor.execute(insert_query) - - if "current_operation" in excluded_table: - insert_query = "insert into current_operation (id) values (0)" - cursor.execute(insert_query) - - if "restore_operation" in excluded_table: - insert_query = "insert into restore_operation (id) values (0)" - cursor.execute(insert_query) - - if "batch_operation" in excluded_table: - insert_query = "insert into batch_operation (id, redo, undo, redo_cs, undo_cs) values (0, '', '', '', '')" - cursor.execute(insert_query) - - if "operation_table" in excluded_table: - insert_query = ( - "insert into operation_table (option) values ('operation')" - ) - cursor.execute(insert_query) - connection.commit() - - def __call__(self, source: str, new: str, excluded_table: [str] = None) -> None: - connection = pg.connect(conninfo=get_pgconn_string(), autocommit=True) - - self.create_database(connection, new) - self.execute_pg_dump("127.0.0.1", source, excluded_table) - self.execute_pg_restore("127.0.0.1", new) - - connection = pg.connect( - conninfo=get_pgconn_string(db_name=new), autocommit=True - ) - self.init_operation_table(connection, excluded_table) - - -def create_project(name: str) -> None: - return copy_project("project", name) - - -def delete_project(name: str) -> None: - with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: - with conn.cursor() as cur: - cur.execute( - f"select pg_terminate_backend(pid) from pg_stat_activity where datname = '{name}'" - ) - cur.execute(f'drop database "{name}"') - - -def clean_project(excluded: list[str] = []) -> None: - projects = list_project() - with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: - with conn.cursor(row_factory=dict_row) as cur: - row = cur.execute(f"select current_database()").fetchone() - if row != None: - current_db = row["current_database"] - if current_db in projects: - projects.remove(current_db) - for project in projects: - if project in _server_databases or project in excluded: - continue - cur.execute( - f"select pg_terminate_backend(pid) from pg_stat_activity where datname = '{project}'" - ) - cur.execute(f'drop database "{project}"') - - -def open_project(name: str) -> None: - if name not in conn: - conn[name] = pg.connect( - conninfo=get_pgconn_string(db_name=name), autocommit=True - ) - - -def is_project_open(name: str) -> bool: - return name in conn - - -def close_project(name: str) -> None: - if name in conn: - conn[name].close() - del conn[name]