完成了第一个版本
This commit is contained in:
parent
dc4d793b08
commit
889a677990
|
|
@ -5,3 +5,6 @@ build/
|
||||||
~$据库本地运行.docx
|
~$据库本地运行.docx
|
||||||
数据库组件本地安装/
|
数据库组件本地安装/
|
||||||
数据库组件本地安装.zip
|
数据库组件本地安装.zip
|
||||||
|
ComacDBInstall.spec
|
||||||
|
src/__pycache__/Test.cpython-311.pyc
|
||||||
|
dist/ComacDBInstall.exe
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
pyinstaller --onefile --add-data "datas/mariadb.zip:datas" --add-data "datas/init.sql:datas" --add-data "datas/jdk.zip:datas" --add-data "datas/start.bat:datas" src/install.py
|
pyinstaller --onefile --add-data "datas/electromagnetic.jar:datas" --add-data "datas/mariadb.zip:datas" --add-data "datas/init.sql:datas" --add-data "datas/jdk.zip:datas" --add-data "datas/start.bat:datas" --add-data "datas/nssm.exe:datas" src/ComacDBInstall.py
|
||||||
pyinstaller --onefile --add-data "datas/electromagnetic.jar:datas" src/start.py
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,272 @@
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import zipfile
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_dir(directory):
|
||||||
|
if not os.path.exists(directory):
|
||||||
|
os.makedirs(directory)
|
||||||
|
logger.info(f"目录 {directory} 已创建")
|
||||||
|
else:
|
||||||
|
logger.info(f"目录 {directory} 已存在")
|
||||||
|
|
||||||
|
def get_resource_path(relative_path):
|
||||||
|
""" 获取资源绝对路径,适用于开发环境和PyInstaller打包后 """
|
||||||
|
if hasattr(sys, '_MEIPASS'):
|
||||||
|
# 打包后的资源路径:sys._MEIPASS + 相对路径
|
||||||
|
base_path = sys._MEIPASS
|
||||||
|
else:
|
||||||
|
# 开发环境的基础路径
|
||||||
|
base_path = os.path.dirname(os.path.abspath("."))
|
||||||
|
return os.path.join(base_path, relative_path)
|
||||||
|
|
||||||
|
def check_service_exist(service_name):
|
||||||
|
result = subprocess.run(['sc', 'query', service_name],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if '1060' in result.stdout: # 服务不存在
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def start_service(service_name):
|
||||||
|
result = subprocess.run(['sc', 'query', service_name],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if 'RUNNING' in result.stdout:
|
||||||
|
logger.info(f"服务 {service_name} 已经在运行")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.info(f"服务 {service_name} 当前未运行")
|
||||||
|
logger.info("尝试启动服务...")
|
||||||
|
|
||||||
|
# 尝试启动服务
|
||||||
|
start_result = subprocess.run(['sc', 'start', service_name],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
|
||||||
|
if start_result.returncode == 0:
|
||||||
|
logger.info(f"服务 {service_name} 启动成功")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.info(f"启动服务 {service_name} 失败: {start_result.stderr}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def unzip_file(zip_file_path):
|
||||||
|
new_path = get_resource_path(os.path.join('datas', 'mariadb.zip'))
|
||||||
|
with zipfile.ZipFile(str(new_path), 'r') as zip_ref:
|
||||||
|
zip_ref.extractall(zip_file_path) # 将文件解压到指定路径
|
||||||
|
|
||||||
|
def start_service_if_not_running(service_name):
|
||||||
|
result = subprocess.run(['sc', 'query', service_name],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if 'RUNNING' in result.stdout:
|
||||||
|
logger.info(f"服务 {service_name} 已经在运行")
|
||||||
|
else:
|
||||||
|
logger.info(f"服务 {service_name} 当前未运行")
|
||||||
|
logger.info("尝试启动服务...")
|
||||||
|
|
||||||
|
# 尝试启动服务
|
||||||
|
start_result = subprocess.run(['sc', 'start', service_name],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
|
||||||
|
if start_result.returncode == 0:
|
||||||
|
logger.info(f"服务 {service_name} 启动成功")
|
||||||
|
else:
|
||||||
|
logger.info(f"启动服务 {service_name} 失败: {start_result.stderr}")
|
||||||
|
raise MyCustomError(rf"服务 {service_name} 启动失败")
|
||||||
|
|
||||||
|
|
||||||
|
class MyCustomError(Exception):
|
||||||
|
"""自定义异常"""
|
||||||
|
|
||||||
|
def __init__(self, message="发生了一个错误"):
|
||||||
|
# 调用基类的构造函数
|
||||||
|
super().__init__(message)
|
||||||
|
|
||||||
|
class InstallMariaDb:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.service_name = 'ComacMariaDB'
|
||||||
|
self.root_path = r'D:\database'
|
||||||
|
self.mariadb_data_path = r'D:\database\mariadb\data'
|
||||||
|
self.mariadb_port = 3417
|
||||||
|
self.passowrd = '1qaz@WSX'
|
||||||
|
self.init_schema = 'em_data_prod'
|
||||||
|
self.init_sql = r'D:/database/mariadb/data/init.sql'
|
||||||
|
pass
|
||||||
|
|
||||||
|
def start_install_mariadb(self):
|
||||||
|
existStatus = check_service_exist(self.service_name)
|
||||||
|
if existStatus:
|
||||||
|
start_service_if_not_running(self.service_name)
|
||||||
|
return
|
||||||
|
logger.info("开始安装MariaDB")
|
||||||
|
ensure_dir(self.root_path)
|
||||||
|
logger.info("开始解压文件")
|
||||||
|
unzip_file(self.root_path)
|
||||||
|
logger.info(f"开始注册服务 {self.service_name}")
|
||||||
|
self.__register_service()
|
||||||
|
logger.info("启动数据库")
|
||||||
|
self.__start_mariadb()
|
||||||
|
logger.info("数据库用户初始化")
|
||||||
|
self.__init_db_user()
|
||||||
|
logger.info("数据库初始化")
|
||||||
|
self.__init_db()
|
||||||
|
logger.info("设置Java运行环境")
|
||||||
|
self.__set_java_env()
|
||||||
|
logger.info("生成脚本文件")
|
||||||
|
self.__set_bat()
|
||||||
|
logger.info("安装完成,10秒后自动退出")
|
||||||
|
time.sleep(10)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __start_mariadb(self):
|
||||||
|
command = 'net start ' + self.service_name
|
||||||
|
with os.popen(command) as stream:
|
||||||
|
res = stream.read()
|
||||||
|
logger.info(res)
|
||||||
|
|
||||||
|
def __register_service(self):
|
||||||
|
args1 = self.root_path + '/mariadb/bin/mysql_install_db.exe'
|
||||||
|
args2 = '--datadir=' + self.mariadb_data_path
|
||||||
|
args3 = '--service=' + self.service_name
|
||||||
|
args4 = '--password=' + self.passowrd
|
||||||
|
args5 = '--port=' + str(self.mariadb_port)
|
||||||
|
res = subprocess.run([args1, args2, args3, args4, args5], text=True, capture_output=True)
|
||||||
|
logger.info(res.stdout)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def __init_db_user(self):
|
||||||
|
command1 = fr'{self.root_path}\mariadb\bin\mysql -u root -p{self.passowrd} -P {self.mariadb_port} -e "create database if not exists {self.init_schema}; use {self.init_schema};"'
|
||||||
|
with os.popen(command1) as stream:
|
||||||
|
res = stream.read()
|
||||||
|
logger.info(res)
|
||||||
|
|
||||||
|
def __init_db(self):
|
||||||
|
new_path = get_resource_path(os.path.join('datas', 'init.sql'))
|
||||||
|
shutil.copy(str(new_path), self.mariadb_data_path)
|
||||||
|
command2 = fr'{self.root_path}\mariadb\bin\mysql --no-defaults -u root -p{self.passowrd} -P {self.mariadb_port} {self.init_schema} < {self.init_sql}'
|
||||||
|
with os.popen(command2) as stream:
|
||||||
|
res2 = stream.read()
|
||||||
|
logger.info(res2)
|
||||||
|
os.remove(self.init_sql)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __set_java_env(self):
|
||||||
|
new_path = get_resource_path(os.path.join('datas', 'jdk.zip'))
|
||||||
|
with zipfile.ZipFile(str(new_path), 'r') as zip_ref:
|
||||||
|
zip_ref.extractall(self.root_path) # 将文件解压到指定路径
|
||||||
|
pass
|
||||||
|
#
|
||||||
|
# def __set_bat(self):
|
||||||
|
# new_path = get_resource_path(os.path.join('datas', 'start.bat'))
|
||||||
|
# shutil.copy(str(new_path), self.root_path)
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
class InstallComacDb:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.project_dir = get_resource_path(os.path.dirname(Path(__file__).parent.absolute()))
|
||||||
|
self.app_log_dir = 'D:/database/logs'
|
||||||
|
self.comac_db_running_port = 12396
|
||||||
|
self.jar_path = get_resource_path(os.path.join("datas", "electromagnetic.jar"))
|
||||||
|
self.new_java_path = 'D:/database/jdk/bin/java.exe'
|
||||||
|
self.url = f'http://127.0.0.1:{self.comac_db_running_port}/index'
|
||||||
|
self.service_name = "comacDatabase"
|
||||||
|
self.service_description = "数据库组件服务"
|
||||||
|
# 路径配置
|
||||||
|
self.datas_dir = get_resource_path(os.path.join('datas'))
|
||||||
|
# NSSM可执行文件路径
|
||||||
|
self.nssm_exe = get_resource_path(os.path.join('datas', 'nssm.exe'))
|
||||||
|
# Java和JAR文件路径
|
||||||
|
self.java_path = "D:/database/jdk/bin/java.exe"
|
||||||
|
ensure_dir(self.app_log_dir)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def start_comac_db(self):
|
||||||
|
self.__delete_old_files(self.app_log_dir)
|
||||||
|
existStatus = check_service_exist(self.service_name)
|
||||||
|
if existStatus:
|
||||||
|
start_service_if_not_running(self.service_name)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.__register_and_start_service()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __delete_old_files(self, directory, days=2):
|
||||||
|
# 计算时间阈值(当前时间 - days天)
|
||||||
|
threshold_time = time.time() - days * 24 * 60 * 60
|
||||||
|
deleted_count = 0
|
||||||
|
try:
|
||||||
|
# 遍历目录中的文件
|
||||||
|
for filename in os.listdir(directory):
|
||||||
|
filepath = os.path.join(directory, filename)
|
||||||
|
|
||||||
|
# 确保是文件而不是目录
|
||||||
|
if os.path.isfile(filepath):
|
||||||
|
try:
|
||||||
|
# 获取文件创建时间(Windows系统)
|
||||||
|
creation_time = os.path.getctime(filepath)
|
||||||
|
|
||||||
|
# 检查文件是否超过阈值
|
||||||
|
if creation_time < threshold_time:
|
||||||
|
# 删除文件
|
||||||
|
os.remove(filepath)
|
||||||
|
deleted_count += 1
|
||||||
|
logger.info(f"已删除: {filename}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(f"处理文件 {filename} 时出错: {str(e)}", file=sys.stderr)
|
||||||
|
|
||||||
|
logger.info(f"\n操作完成!共删除 {deleted_count} 个日志文件。")
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(f"遍历目录时出错: {str(e)}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def __register_and_start_service(self):
|
||||||
|
# 服务配置
|
||||||
|
# 构建NSSM安装命令
|
||||||
|
formatted_time = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
cmd = [
|
||||||
|
str(self.nssm_exe),
|
||||||
|
"install",
|
||||||
|
self.service_name,
|
||||||
|
self.java_path,
|
||||||
|
f"-jar {self.jar_path} --logging.file.path={self.app_log_dir} --logging.file.name={self.app_log_dir}/app_{formatted_time}.log"
|
||||||
|
]
|
||||||
|
|
||||||
|
# 执行安装命令
|
||||||
|
print("Installing service...")
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("Error installing service:")
|
||||||
|
print(result.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("Service installed successfully!")
|
||||||
|
|
||||||
|
# 设置服务显示名称和描述
|
||||||
|
subprocess.run([str(self.nssm_exe), "set", self.service_name, "DisplayName", self.service_name])
|
||||||
|
subprocess.run([str(self.nssm_exe), "set", self.service_name, "Description", self.service_description])
|
||||||
|
|
||||||
|
# 设置启动目录(可选,但推荐)
|
||||||
|
# subprocess.run([str(nssm_exe), "set", service_name, "AppDirectory", str(datas_dir)])
|
||||||
|
|
||||||
|
# 设置启动类型为自动(可选)
|
||||||
|
subprocess.run([str(self.nssm_exe), "set", self.service_name, "Start", "SERVICE_AUTO_START"])
|
||||||
|
|
||||||
|
print("Service configuration completed.")
|
||||||
|
print(f"You can now start the service with: net start {self.service_name}")
|
||||||
|
subprocess.run(rf"net start {self.service_name}")
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
InstallMariaDb().start_install_mariadb()
|
||||||
|
InstallComacDb().start_comac_db()
|
||||||
|
pass
|
||||||
|
|
@ -7,6 +7,7 @@ import loguru
|
||||||
import elevate
|
import elevate
|
||||||
import shutil
|
import shutil
|
||||||
import psutil
|
import psutil
|
||||||
|
import re
|
||||||
|
|
||||||
root_path = r'D:\database'
|
root_path = r'D:\database'
|
||||||
service_name = 'ComacMariaDB'
|
service_name = 'ComacMariaDB'
|
||||||
|
|
@ -15,6 +16,8 @@ mariadb_data_path = r'D:\database\mariadb\data'
|
||||||
init_sql = r'D:/database/mariadb/data/init.sql'
|
init_sql = r'D:/database/mariadb/data/init.sql'
|
||||||
mariadb_port = 3417
|
mariadb_port = 3417
|
||||||
init_schema = 'em_data_prod'
|
init_schema = 'em_data_prod'
|
||||||
|
db_running_port=12396
|
||||||
|
db_running_service_name="ComacDataBase"
|
||||||
|
|
||||||
def ensure_dir(directory):
|
def ensure_dir(directory):
|
||||||
if not os.path.exists(directory):
|
if not os.path.exists(directory):
|
||||||
|
|
@ -103,6 +106,7 @@ def start_install():
|
||||||
status = check_service()
|
status = check_service()
|
||||||
if status:
|
if status:
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
loguru.logger.info("开始安装MariaDB")
|
loguru.logger.info("开始安装MariaDB")
|
||||||
ensure_dir(root_path)
|
ensure_dir(root_path)
|
||||||
loguru.logger.info("开始解压文件")
|
loguru.logger.info("开始解压文件")
|
||||||
|
|
@ -122,6 +126,46 @@ def start_install():
|
||||||
loguru.logger.info("安装完成,10秒后自动退出")
|
loguru.logger.info("安装完成,10秒后自动退出")
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
|
|
||||||
|
def check_service_exists(query_service_name):
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(['sc', 'query', query_service_name], stderr=subprocess.STDOUT)
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
if '1060' in str(e.output): # 错误代码1060表示服务不存在
|
||||||
|
return False
|
||||||
|
raise
|
||||||
|
|
||||||
|
def start_app():
|
||||||
|
|
||||||
|
# 首先检查有没有数据库运行的服务名,如果没有,则需要创建,
|
||||||
|
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def kill_process_by_port(run_port):
|
||||||
|
# 执行netstat命令获取端口占用信息
|
||||||
|
cmd_netstat = ['netstat', '-ano', '|', 'findstr', fr':{run_port}']
|
||||||
|
result = subprocess.run(cmd_netstat, capture_output=True, text=True, shell=True)
|
||||||
|
out = result.stdout
|
||||||
|
if out:
|
||||||
|
arr = re.split(r'\s+', out)
|
||||||
|
pid = arr[5]
|
||||||
|
if pid:
|
||||||
|
try:
|
||||||
|
subprocess.run(['taskkill', '/F', '/PID', pid], check=True)
|
||||||
|
loguru.logger.info(f"已终止占用端口 {run_port} 的进程 (PID: {pid})")
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
loguru.logger.info(f"终止进程 {pid} 失败 (可能权限不足或进程不存在)")
|
||||||
|
else:
|
||||||
|
loguru.logger.info(f"端口 {run_port} 未被占用")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
elevate.elevate()
|
elevate.elevate()
|
||||||
start_install()
|
start_install()
|
||||||
|
start_app()
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ def start():
|
||||||
creationflags=creation_flags
|
creationflags=creation_flags
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"应用已在后台启动! PID: {process.pid}")
|
logger.info(f"应用正在启动! PID: {process.pid}")
|
||||||
logger.info(f"日志输出: {os.path.abspath(log_file)}")
|
logger.info(f"日志输出: {os.path.abspath(log_file)}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(f"启动失败: {str(e)}")
|
logger.info(f"启动失败: {str(e)}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue