上传文件至「full」
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
from PyInstaller.utils.hooks import collect_all
|
||||||
|
|
||||||
|
# 强制收集 PyQt5 全部模块及二进制文件
|
||||||
|
qt_datas, qt_binaries, qt_hiddenimports = collect_all('PyQt5')
|
||||||
|
|
||||||
|
# 自定义 manifest:要求管理员 + 声明 PerMonitorV2 DPI 感知,
|
||||||
|
# 避免程序在不同缩放比例的显示器之间移动时被 Windows 位图拉伸。
|
||||||
|
_MANIFEST = r'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="RRPP" type="win32"/>
|
||||||
|
<description>Royirin Rosmontis Private Proxy</description>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor, system</dpiAwareness>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
||||||
|
'''
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['proxy.py'],
|
||||||
|
pathex=['.venv\\Lib\\site-packages'],
|
||||||
|
binaries=qt_binaries,
|
||||||
|
datas=[('jp_client.conf', '.'), ('wg', 'wg'), ('ico.ico', '.')] + qt_datas,
|
||||||
|
hiddenimports=qt_hiddenimports,
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='Royirin Rosmontis Private Proxy',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
# UPX 会压缩资源段(含图标),冷缓存下 Explorer 可能提取不到图标导致任务栏空白
|
||||||
|
upx=False,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
uac_admin=True,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon=['ico.ico'],
|
||||||
|
manifest=_MANIFEST,
|
||||||
|
)
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
RRPP 发布上传脚本
|
||||||
|
|
||||||
|
负责把 PyInstaller 打包好的 EXE 上传到服务器,并更新 latest_version.json,
|
||||||
|
使客户端启动时能检测并下载新版本。
|
||||||
|
|
||||||
|
## 服务器连接信息
|
||||||
|
|
||||||
|
主机: 172.207.81.145
|
||||||
|
端口: 22
|
||||||
|
用户: RRRosmontis
|
||||||
|
密码: ftA406u@all#2309
|
||||||
|
|
||||||
|
服务器可能启用了键盘交互认证,sshpass 等非交互式工具会报 Permission denied,
|
||||||
|
因此使用 .venv 中的 paramiko 进行 SSH/SFTP。
|
||||||
|
|
||||||
|
## 完整发布流程
|
||||||
|
|
||||||
|
1. 修改 proxy.py 与本脚本中的 VERSION 为当前年月日时分(例如 202607022100)。
|
||||||
|
2. 重新打包 EXE:
|
||||||
|
.venv/Scripts/python.exe -m PyInstaller RRPP.spec --noconfirm
|
||||||
|
或双击运行 build.bat,输出统一在 dist/ 目录。
|
||||||
|
3. 运行本脚本上传并更新服务器版本信息:
|
||||||
|
.venv/Scripts/python.exe upload_to_server.py
|
||||||
|
|
||||||
|
脚本执行步骤:
|
||||||
|
- SSH 连接到 172.207.81.145
|
||||||
|
- 把 dist/Royirin Rosmontis Private Proxy.exe 上传到 /tmp/proxy.exe
|
||||||
|
- 用 sudo 创建 /var/www/html/release/<VERSION>/ 并移动 EXE
|
||||||
|
- 用 sudo 写入 /var/www/html/latest_version.json(https 下载链接)
|
||||||
|
- 回显服务器上的 latest_version.json 内容用于验证
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 上传前请确保 dist/ 下的 EXE 已重新打包,且版本号与 VERSION 一致。
|
||||||
|
- 若服务器连接信息或证书有变,请修改下方的 HOST / PORT / USER / PASSWORD。
|
||||||
|
"""
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import paramiko
|
||||||
|
|
||||||
|
# ── 服务器连接与版本配置 ───────────────────────────────
|
||||||
|
HOST = "172.207.81.145"
|
||||||
|
PORT = 22
|
||||||
|
USER = "RRRosmontis"
|
||||||
|
PASSWORD = "ftA406u@all#2309"
|
||||||
|
VERSION = "202607192300"
|
||||||
|
|
||||||
|
# ── 本地 / 远程路径 ────────────────────────────────────
|
||||||
|
LOCAL_EXE = Path("dist/Royirin Rosmontis Private Proxy.exe")
|
||||||
|
REMOTE_DIR = f"/var/www/html/release/{VERSION}"
|
||||||
|
REMOTE_EXE_NAME = "Royirin Rosmontis Private Proxy.exe"
|
||||||
|
REMOTE_JSON = "/var/www/html/latest_version.json"
|
||||||
|
|
||||||
|
|
||||||
|
def sudo_exec(client, command, password, timeout=30):
|
||||||
|
"""通过 sudo -S 执行远程命令,并从 stdin 传入密码。"""
|
||||||
|
cmd = f"sudo -S bash -c {shlex.quote(command)}"
|
||||||
|
stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout)
|
||||||
|
stdin.write(password + "\n")
|
||||||
|
stdin.flush()
|
||||||
|
stdin.channel.shutdown_write()
|
||||||
|
|
||||||
|
exit_status = stdout.channel.recv_exit_status()
|
||||||
|
out = stdout.read().decode("utf-8", errors="replace")
|
||||||
|
err = stderr.read().decode("utf-8", errors="replace")
|
||||||
|
return exit_status, out, err
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主流程:上传 EXE 并更新服务器 latest_version.json。"""
|
||||||
|
if not LOCAL_EXE.exists():
|
||||||
|
print(f"错误:本地文件不存在: {LOCAL_EXE}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"连接 {HOST}:{PORT} ...")
|
||||||
|
client = paramiko.SSHClient()
|
||||||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
client.connect(HOST, port=PORT, username=USER, password=PASSWORD)
|
||||||
|
print("SSH 连接成功")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. 上传 EXE 到 /tmp
|
||||||
|
remote_tmp = "/tmp/proxy.exe"
|
||||||
|
print(f"上传 {LOCAL_EXE} -> {remote_tmp} ...")
|
||||||
|
sftp = client.open_sftp()
|
||||||
|
sftp.put(str(LOCAL_EXE), remote_tmp)
|
||||||
|
sftp.close()
|
||||||
|
print("上传完成")
|
||||||
|
|
||||||
|
# 2. 创建发布目录并移动文件到最终位置
|
||||||
|
print(f"创建目录 {REMOTE_DIR} 并移动 EXE ...")
|
||||||
|
cmd = f"mkdir -p {REMOTE_DIR} && mv {remote_tmp} '{REMOTE_DIR}/{REMOTE_EXE_NAME}'"
|
||||||
|
status, out, err = sudo_exec(client, cmd, PASSWORD)
|
||||||
|
if status != 0:
|
||||||
|
print(f"移动文件失败: {err}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
print("文件已移动到发布目录")
|
||||||
|
|
||||||
|
# 3. 更新 latest_version.json,客户端据此检测新版本
|
||||||
|
json_content = (
|
||||||
|
'{"latest_version":"' + VERSION + '",'
|
||||||
|
'"download_url":"https://tunnel.rrrosmontis.icu/release/'
|
||||||
|
+ VERSION + '/Royirin%20Rosmontis%20Private%20Proxy.exe"}'
|
||||||
|
)
|
||||||
|
print(f"更新 {REMOTE_JSON} ...")
|
||||||
|
cmd = f"echo '{json_content}' | tee {REMOTE_JSON}"
|
||||||
|
status, out, err = sudo_exec(client, cmd, PASSWORD)
|
||||||
|
if status != 0:
|
||||||
|
print(f"更新 JSON 失败: {err}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
print("latest_version.json 已更新")
|
||||||
|
print(f"服务器返回: {out.strip()}")
|
||||||
|
|
||||||
|
# 4. 验证远程 JSON 内容
|
||||||
|
print("验证远程文件...")
|
||||||
|
stdin, stdout, stderr = client.exec_command(f"cat {REMOTE_JSON}")
|
||||||
|
print(stdout.read().decode("utf-8").strip())
|
||||||
|
|
||||||
|
finally:
|
||||||
|
client.close()
|
||||||
|
print("连接已关闭")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user