From 42734f8ceab8c38a8c711ab15e25085b03daeccb Mon Sep 17 00:00:00 2001 From: lou Date: Mon, 10 Aug 2026 19:44:45 +0800 Subject: [PATCH] =?UTF-8?q?7z=20=E5=8E=8B=E7=BC=A9=E6=97=A5=E5=BF=97:=20pt?= =?UTF-8?q?y=20=E8=BF=90=E8=A1=8C(=E9=9D=9Etty=E4=B9=9F=E8=BE=93=E5=87=BAb?= =?UTF-8?q?anner)=20+=20=E5=8E=8B=E7=BC=A9=E5=AE=8C=E6=88=90=E6=97=A5?= =?UTF-8?q?=E5=BF=97(=E5=A4=A7=E5=B0=8F/=E5=8E=8B=E7=BC=A9=E7=8E=87/?= =?UTF-8?q?=E8=80=97=E6=97=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup.py | 40 +++++++++++++++++-- debian/7z-encrypt-client/DEBIAN/control | 2 +- debian/7z-encrypt-client/DEBIAN/md5sums | 2 +- .../usr/share/7z-encrypt/backup.py | 40 +++++++++++++++++-- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/backup.py b/backup.py index be57905..fb13f76 100644 --- a/backup.py +++ b/backup.py @@ -19,6 +19,7 @@ import os import subprocess import sys import tarfile +import time from datetime import datetime from pathlib import Path from typing import Any @@ -33,10 +34,35 @@ COMPRESS_SUFFIX = {".db", ".sqlite", ".sqlite3", ".sql", ".txt", ".json", ".xml" def _7z(args: list[str]) -> None: - """调系统 7z (p7zip-full), 实时透传进度输出 (7z 自带百分比进度条)""" - r = subprocess.run(["7z"] + args) - if r.returncode != 0: - raise RuntimeError(f"7z 失败 (exit {r.returncode})") + """调系统 7z (p7zip-full), pty 运行保证百分比进度输出 + + SSH/管道 (非 tty) 下 7z 默认不输出百分比进度条, pty 模拟终端 + 让 7z 始终输出 0%..100% 实时进度, 透传到 stdout。 + """ + import os as _os + import pty as _pty + cmd = ["7z"] + args + master, slave = _pty.openpty() + proc: subprocess.Popen | None = None + try: + proc = subprocess.Popen(cmd, stdout=slave, stderr=slave, close_fds=True) + _os.close(slave) + try: + while True: + try: + data = _os.read(master, 4096) + except OSError: + break + if not data: + break + sys.stdout.write(data.decode(errors="replace")) + sys.stdout.flush() + proc.wait() + finally: + _os.close(master) + finally: + if proc is not None and proc.returncode != 0: + raise RuntimeError(f"7z 失败 (exit {proc.returncode})") def _cfg() -> dict[str, Any]: @@ -242,8 +268,14 @@ def backup(name: str, chunk_mb: int = 10) -> int: # 7z 压缩 (与上传文件一致): 含文本类 -mx=9, 照片视频 -mx=1 mx = 9 if any(_compress(f) for f in batch) else 1 seven = tar_path.with_suffix(".tar.7z") + raw_mb = tar_path.stat().st_size / 1048576 print(f"[备份] 7z 压缩 (mx={mx}) ...") + _t0 = time.time() _7z(["a", "-y", "-bd", f"-mx={mx}", str(seven), str(tar_path)]) + _dt = time.time() - _t0 + sz_mb = seven.stat().st_size / 1048576 + print(f"[备份] 7z 压缩完成: {raw_mb:.1f} MB -> {sz_mb:.1f} MB " + f"(压缩率 {sz_mb / raw_mb * 100:.0f}%), 耗时 {_dt:.1f}s") tar_path.unlink(missing_ok=True) tar_path = seven size_mb = tar_path.stat().st_size / 1048576 diff --git a/debian/7z-encrypt-client/DEBIAN/control b/debian/7z-encrypt-client/DEBIAN/control index 9c26585..4d0de0a 100644 --- a/debian/7z-encrypt-client/DEBIAN/control +++ b/debian/7z-encrypt-client/DEBIAN/control @@ -2,7 +2,7 @@ Package: 7z-encrypt-client Version: 1.0.0 Architecture: all Maintainer: edgevoid -Installed-Size: 126 +Installed-Size: 127 Depends: python3 (>= 3.10), python3-venv, p7zip-full Section: utils Priority: optional diff --git a/debian/7z-encrypt-client/DEBIAN/md5sums b/debian/7z-encrypt-client/DEBIAN/md5sums index f0de9a9..c801fea 100644 --- a/debian/7z-encrypt-client/DEBIAN/md5sums +++ b/debian/7z-encrypt-client/DEBIAN/md5sums @@ -2,7 +2,7 @@ 440c53f84f5722b5146959c8fc6d7a23 usr/bin/sz-config ec8cf0df841e479689ccb681f6168ccc usr/bin/sz-transfer 0ba5b8147990daa7fd07344952c42847 usr/bin/sz-tui -d0faeb4f34bb1cec041c9a4616e529be usr/share/7z-encrypt/backup.py +d94c79eeda7a87a620c1f24181e06359 usr/share/7z-encrypt/backup.py dcb31e74e0a6ee8073337fc4fb2acf99 usr/share/7z-encrypt/config.py 8a064c0b3c21d50812a3fd69a320d862 usr/share/7z-encrypt/crypto.py 21062e04f8c7f4471881a39c489dfa73 usr/share/7z-encrypt/metadata.py diff --git a/debian/7z-encrypt-client/usr/share/7z-encrypt/backup.py b/debian/7z-encrypt-client/usr/share/7z-encrypt/backup.py index be57905..fb13f76 100644 --- a/debian/7z-encrypt-client/usr/share/7z-encrypt/backup.py +++ b/debian/7z-encrypt-client/usr/share/7z-encrypt/backup.py @@ -19,6 +19,7 @@ import os import subprocess import sys import tarfile +import time from datetime import datetime from pathlib import Path from typing import Any @@ -33,10 +34,35 @@ COMPRESS_SUFFIX = {".db", ".sqlite", ".sqlite3", ".sql", ".txt", ".json", ".xml" def _7z(args: list[str]) -> None: - """调系统 7z (p7zip-full), 实时透传进度输出 (7z 自带百分比进度条)""" - r = subprocess.run(["7z"] + args) - if r.returncode != 0: - raise RuntimeError(f"7z 失败 (exit {r.returncode})") + """调系统 7z (p7zip-full), pty 运行保证百分比进度输出 + + SSH/管道 (非 tty) 下 7z 默认不输出百分比进度条, pty 模拟终端 + 让 7z 始终输出 0%..100% 实时进度, 透传到 stdout。 + """ + import os as _os + import pty as _pty + cmd = ["7z"] + args + master, slave = _pty.openpty() + proc: subprocess.Popen | None = None + try: + proc = subprocess.Popen(cmd, stdout=slave, stderr=slave, close_fds=True) + _os.close(slave) + try: + while True: + try: + data = _os.read(master, 4096) + except OSError: + break + if not data: + break + sys.stdout.write(data.decode(errors="replace")) + sys.stdout.flush() + proc.wait() + finally: + _os.close(master) + finally: + if proc is not None and proc.returncode != 0: + raise RuntimeError(f"7z 失败 (exit {proc.returncode})") def _cfg() -> dict[str, Any]: @@ -242,8 +268,14 @@ def backup(name: str, chunk_mb: int = 10) -> int: # 7z 压缩 (与上传文件一致): 含文本类 -mx=9, 照片视频 -mx=1 mx = 9 if any(_compress(f) for f in batch) else 1 seven = tar_path.with_suffix(".tar.7z") + raw_mb = tar_path.stat().st_size / 1048576 print(f"[备份] 7z 压缩 (mx={mx}) ...") + _t0 = time.time() _7z(["a", "-y", "-bd", f"-mx={mx}", str(seven), str(tar_path)]) + _dt = time.time() - _t0 + sz_mb = seven.stat().st_size / 1048576 + print(f"[备份] 7z 压缩完成: {raw_mb:.1f} MB -> {sz_mb:.1f} MB " + f"(压缩率 {sz_mb / raw_mb * 100:.0f}%), 耗时 {_dt:.1f}s") tar_path.unlink(missing_ok=True) tar_path = seven size_mb = tar_path.stat().st_size / 1048576