bcmd 0.6.9__py3-none-any.whl → 0.6.10__py3-none-any.whl

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.

Potentially problematic release.


This version of bcmd might be problematic. Click here for more details.

bcmd/common/func.py CHANGED
@@ -15,5 +15,5 @@ def checkPathOrNotExists(folder: Path):
15
15
 
16
16
  @contextmanager
17
17
  def useResources(name: str):
18
- with importlib.resources.path('bcmdx.resources', name) as target:
18
+ with importlib.resources.path('bcmd.resources', name) as target:
19
19
  yield target
bcmd/tasks/__init__.py CHANGED
@@ -3,6 +3,7 @@ from . import bin
3
3
  from . import code
4
4
  from . import crypto
5
5
  from . import debian
6
+ from . import docs
6
7
  from . import download
7
8
  from . import image
8
9
  from . import json
bcmd/tasks/docs.py ADDED
@@ -0,0 +1,185 @@
1
+ import asyncio
2
+ import datetime
3
+ import pickle
4
+ import tkinter as tk
5
+ from contextlib import asynccontextmanager
6
+ from pathlib import Path
7
+ from tkinter import messagebox
8
+ from typing import Any, Final
9
+ from uuid import uuid4
10
+
11
+ import paramiko
12
+ from beni import bcolor, bcrypto, bfile, bpath, brun, btask, bzip
13
+ from beni.bform import BForm
14
+ from beni.bfunc import syncCall
15
+ from typer import Argument
16
+
17
+ from bcmd.utils.utils import decryptFileIgnoreError
18
+
19
+ app: Final = btask.newSubApp('Vitepress 网站相关')
20
+ conf: dict[str, Any] = {}
21
+ isUpload: bool = False
22
+ password: str = ''
23
+ now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
24
+
25
+ projectPath = bpath.get('')
26
+ docsPath = bpath.get('')
27
+ vitepressDistPath = bpath.get('')
28
+ distPath = bpath.get('')
29
+ deployPath = bpath.get('')
30
+ zipFile = bpath.get('')
31
+
32
+
33
+ @app.command()
34
+ @syncCall
35
+ async def build(
36
+ path: Path = Argument(Path.cwd(), help='workspace 路径'),
37
+ ):
38
+ '发布'
39
+ with bpath.useTempPath(True) as tempPath:
40
+ await init(path)
41
+ await userInput()
42
+ await vitepressBuild(tempPath / 'site')
43
+ await makeDeploy(tempPath / 'deploy')
44
+ for file in bpath.listPath(tempPath):
45
+ await bzip.sevenZip(zipFile, file)
46
+ if isUpload:
47
+ await upload()
48
+ bcolor.printGreen('OK')
49
+
50
+
51
+ async def init(path: Path):
52
+ global projectPath, docsPath, vitepressDistPath, distPath, deployPath, conf, zipFile
53
+
54
+ # 初始化目录路径
55
+ projectPath = path
56
+ docsPath = projectPath / 'docs'
57
+ vitepressDistPath = docsPath / '.vitepress/dist'
58
+ distPath = projectPath / 'dist'
59
+ deployPath = projectPath / 'deploy'
60
+
61
+ # 清空打包用到的目录
62
+ bpath.remove(distPath)
63
+ bpath.make(distPath)
64
+ bpath.remove(vitepressDistPath)
65
+
66
+ # 更新配置
67
+ infoTomlFile = deployPath / 'info.toml'
68
+ if not infoTomlFile.exists():
69
+ btask.abort('部署文件不存在', infoTomlFile)
70
+ conf.update(await bfile.readToml(infoTomlFile))
71
+
72
+ # 整理特殊的字段
73
+ zipFile = distPath / f'{conf['domain']}_{now}.7z'
74
+ conf['upload_file_name'] = zipFile.name
75
+ conf['temp_path'] += f'/{uuid4()}'
76
+
77
+
78
+ async def userInput():
79
+ global isUpload, password
80
+
81
+ class BuildForm(BForm):
82
+ def __init__(self):
83
+ super().__init__(title='发布网站')
84
+ self.varIsUpload = tk.BooleanVar(value=True)
85
+ self.varPassword = tk.StringVar(value='')
86
+ self.addLabel('网站', conf['domain'])
87
+ self.addCheckBox('上传服务器', '', self.varIsUpload)
88
+ self.addEntry('请输入密码', self.varPassword, width=20, command=self.onBtn, password=True, focus=True)
89
+
90
+ def onBtn(self):
91
+ password = self.varPassword.get()
92
+ try:
93
+ conf['server_info'] = bcrypto.decryptJson(conf['server_info'], password)
94
+ self.destroy()
95
+ except:
96
+ messagebox.showerror('密码错误', '密码错误,请重新输入')
97
+
98
+ def getResult(self):
99
+ return self.varIsUpload.get(), self.varPassword.get()
100
+
101
+ isUpload, password = BuildForm().run()
102
+
103
+ # 配置里面每个字段都尝试解密(实际效率较低但不影响使用)
104
+ for k, v in conf.items():
105
+ try:
106
+ conf[k] = bcrypto.decryptText(v, password)
107
+ except:
108
+ pass
109
+
110
+
111
+ async def vitepressBuild(outputPath: Path):
112
+ with bpath.changePath(projectPath):
113
+ await brun.run('pnpm install')
114
+ await brun.run('pnpm docs:build')
115
+ bpath.copy(vitepressDistPath, outputPath)
116
+
117
+
118
+ async def makeDeploy(outputPath: Path):
119
+ bpath.copy(projectPath / 'deploy', outputPath)
120
+ bpath.remove(outputPath / 'info.toml')
121
+
122
+ # 删除配置里面加密和删除非字符串的配置,剩下的内容用于替换文件名和文件内容
123
+ dataDict: dict[str, Any] = pickle.loads(pickle.dumps(conf))
124
+ for k in list(dataDict.keys()):
125
+ v = dataDict[k]
126
+ if not isinstance(v, str):
127
+ del dataDict[k]
128
+
129
+ # 文件名以及内容调整
130
+ fileList = bpath.listFile(outputPath, True)
131
+ await asyncio.gather(*[decryptFileIgnoreError(x, password) for x in fileList])
132
+ for file in fileList:
133
+
134
+ # 替换文件名
135
+ toFile = str(file)
136
+ for k, v in dataDict.items():
137
+ toFile = toFile.replace(f'{{{k}}}', str(v))
138
+ if toFile != str(file):
139
+ file.rename(toFile)
140
+ file = bpath.get(toFile)
141
+
142
+ # 替换文件内容
143
+ content = await bfile.readText(file)
144
+ oldContent = content
145
+ for k, v in dataDict.items():
146
+ content = content.replace(f'{{{k}}}', str(v))
147
+ if oldContent != content:
148
+ await bfile.writeText(file, content)
149
+
150
+ # 将 Scrips 里面的文件都抽离到 dist 目录
151
+ scriptsPath = outputPath / 'Scripts'
152
+ for file in bpath.listFile(scriptsPath):
153
+ bpath.move(file, distPath / f'{conf['domain']}_{now}_{file.stem}{file.suffix}')
154
+ bpath.remove(scriptsPath)
155
+
156
+
157
+ @asynccontextmanager
158
+ async def sshClient():
159
+ client = paramiko.SSHClient()
160
+ client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
161
+ with bpath.useTempFile() as tempFile:
162
+ await bfile.writeText(tempFile, conf['server_key'])
163
+ client.connect(
164
+ **conf['server_info'],
165
+ key_filename=str(tempFile),
166
+ )
167
+ yield client
168
+ client.close()
169
+
170
+
171
+ async def upload():
172
+ async with sshClient() as client:
173
+
174
+ def executeCmd(cmd: str):
175
+ _, stdout, _ = client.exec_command(f"bash -lc '{cmd}'")
176
+ print(stdout.read().decode())
177
+
178
+ sftp = client.open_sftp()
179
+ for file in bpath.listFile(distPath):
180
+ executeCmd(f'mkdir -p {conf['temp_path']}')
181
+ sftp.put(str(file), f'{conf['temp_path']}/{file.name}')
182
+ shFile = list(distPath.glob('*.sh'))[0]
183
+ executeCmd(f'sh {conf['temp_path']}/{shFile.name}')
184
+ executeCmd(f'rm -rf {conf['temp_path']}')
185
+ sftp.close()
bcmd/tasks/upgrade.py CHANGED
@@ -11,11 +11,10 @@ app: Final = btask.app
11
11
  @app.command()
12
12
  @syncCall
13
13
  async def upgrade(
14
- name: str = typer.Argument('bcmdx', help='要更新的包名'),
14
+ name: str = typer.Argument('bcmd', help='要更新的包名'),
15
15
  ):
16
- '使用 pipx 官方源更新指定包到最新版本'
17
-
18
- cmd = f'pipx upgrade {name} -i https://pypi.org/simple'
16
+ '使用 uv 官方源更新指定包到最新版本'
17
+ cmd = f'uv tool install -U --index https://pypi.org/simple {name}'
19
18
  pyperclip.copy(cmd + '\n')
20
19
  bcolor.printGreen(cmd)
21
20
  bcolor.printGreen('已复制到剪贴板(需要手动执行)')
bcmd/utils/utils.py ADDED
@@ -0,0 +1,9 @@
1
+ from beni import bcrypto
2
+ from beni.btype import XPath
3
+
4
+
5
+ async def decryptFileIgnoreError(file: XPath, password: str):
6
+ try:
7
+ await bcrypto.decryptFile(file, password)
8
+ except:
9
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bcmd
3
- Version: 0.6.9
3
+ Version: 0.6.10
4
4
  Summary: Commands for Beni
5
5
  Author-email: Beni Mang <benimang@126.com>
6
6
  Maintainer-email: Beni Mang <benimang@126.com>
@@ -11,6 +11,7 @@ Requires-Dist: async-lru==2.0.5
11
11
  Requires-Dist: benimang==0.8.6
12
12
  Requires-Dist: cryptography==45.0.4
13
13
  Requires-Dist: nest-asyncio==1.6.0
14
+ Requires-Dist: paramiko==3.5.1
14
15
  Requires-Dist: pillow==11.2.1
15
16
  Requires-Dist: prettytable==3.16.0
16
17
  Requires-Dist: psutil==7.0.0
@@ -1,13 +1,14 @@
1
1
  bcmd/__init__.py,sha256=GP_60-6vImXqdMfC5vc4xlscWajx4OYmnlNXASWn19w,147
2
2
  bcmd/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- bcmd/common/func.py,sha256=MB_ChA4aRzEjhMhyFmZ-h8aOZePzk0poYcTYRJUQxmI,509
3
+ bcmd/common/func.py,sha256=MehbfuWFHTOsihhYxVFj0_U6-hjMTfLh3n-oMrpyyKo,508
4
4
  bcmd/common/secret.py,sha256=clemEVTCl3shhRBgjKZfrtTdyODz5U-wOyHfUXPegG4,1692
5
5
  bcmd/resources/project/main.py,sha256=xdskz_sf05fYA1SRMFCIxDjx8SnegxTbCmHpW86ItLs,11
6
- bcmd/tasks/__init__.py,sha256=lcVrTgdEph3tKBwwCPVyEOHp-1A3zdFA_6OWLrOo19M,314
6
+ bcmd/tasks/__init__.py,sha256=_G8hO9P0UEKJRreXv8114XeTR8uFG8gRSjvA1WMv8f8,333
7
7
  bcmd/tasks/bin.py,sha256=DufZGRX7b2zclSaZM-zUPGwOiycN9RsV8KxF8tfSyqs,3240
8
8
  bcmd/tasks/code.py,sha256=IUs_ClZuSsBk2gavlitC8mkRrQQX9rvNDgR8cFxduBA,3992
9
9
  bcmd/tasks/crypto.py,sha256=LKvgsMPLvsi1wlt66TinYiN-oV2IPAfaN9y7hWaVpHs,2951
10
10
  bcmd/tasks/debian.py,sha256=B9aMIIct3vNqMJr5hTr1GegXVf20H49C27FMvRRGIzI,3004
11
+ bcmd/tasks/docs.py,sha256=pVs9iy9fjo4DrWX-YfrxjnxLOO4VAW7w5NUqIZHxnVQ,5927
11
12
  bcmd/tasks/download.py,sha256=XdZYKi8zQTNYWEgUxeTNDqPgP7IGYJkMmlDDC9u93Vk,2315
12
13
  bcmd/tasks/image.py,sha256=_ck-WVfUlyQ2fZTpVPcpcurWSud7AkANKUuFjMW7MwA,14283
13
14
  bcmd/tasks/json.py,sha256=WWOyvcZPYaqQgp-Tkm-uIJschNMBKPKtZN3yXz_SC5s,635
@@ -17,16 +18,17 @@ bcmd/tasks/mirror.py,sha256=nAe8NYftMKzht16MFBj7RqXwvVhR6Jh2uuAyJLh87og,1098
17
18
  bcmd/tasks/pdf.py,sha256=fkHRgxqzrRxdb4_-9pL9wp2roqAHJPS_dVqAGJvRUsM,1504
18
19
  bcmd/tasks/proxy.py,sha256=KDOXtNRoY4n45tBrAgK-UM7GmvCCx3Ho545yxMc8PKQ,1602
19
20
  bcmd/tasks/time.py,sha256=ZiqA1jdgl-TBtFSOxxP51nwv4g9iZItmkFKpf9MKelk,2453
20
- bcmd/tasks/upgrade.py,sha256=z9Ein8U_Co7fsijPxyDFM8tXBFCp4bWATImwwwvC5ho,536
21
+ bcmd/tasks/upgrade.py,sha256=nyhcl5oGAUnOOR8JJZW2jfepcVJ6O9gufK8VgxUeil0,543
21
22
  bcmd/tasks/wasabi.py,sha256=xWFAxprSIlBqDDMGaNXZFb-SahnW1d_R9XxSKRYIhnM,3110
22
23
  bcmd/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ bcmd/utils/utils.py,sha256=Oyf5ubxaCD_T2GOz3zJkR4AJzfVcfBqtmL8Gk8_gOJs,202
23
25
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
26
  test/conftest.py,sha256=grlPunlsvrkt_8QPckmF4POiKUPVxIxm2TPAh_ZB-zs,405
25
27
  test/test_pdf.py,sha256=7yYlfydyhy2dmVYdTA5Vir2AI8TUdzEi55fL-AqJmio,1533
26
28
  test/test_proxy.py,sha256=UMF2hFFGUEbJR1jT2mO_wdo-7Rfp0NDqIdTRnOmwtjY,164
27
29
  test/test_wasabi.py,sha256=qqXG1Kb9hKH6t624R173j6LagkgmejN0CFYt7kL0nNs,1066
28
- bcmd-0.6.9.dist-info/METADATA,sha256=dUP3hFm6hT4tvf13ubEiaPvjyA5tloVlls7RlQQiNTE,812
29
- bcmd-0.6.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- bcmd-0.6.9.dist-info/entry_points.txt,sha256=mriCeYh3wksKcqq3-LtzyFkSCIdN1uZc1IJwom-SW1s,34
31
- bcmd-0.6.9.dist-info/top_level.txt,sha256=fYY6tRrJ_G7tn24RXAG0M5ZKbcuaQznodfX1toFPSKs,10
32
- bcmd-0.6.9.dist-info/RECORD,,
30
+ bcmd-0.6.10.dist-info/METADATA,sha256=x2T8YTvQ8vQxS0aiegxZNmPoMgqp76gyfeBpRYd79l4,845
31
+ bcmd-0.6.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ bcmd-0.6.10.dist-info/entry_points.txt,sha256=mriCeYh3wksKcqq3-LtzyFkSCIdN1uZc1IJwom-SW1s,34
33
+ bcmd-0.6.10.dist-info/top_level.txt,sha256=fYY6tRrJ_G7tn24RXAG0M5ZKbcuaQznodfX1toFPSKs,10
34
+ bcmd-0.6.10.dist-info/RECORD,,
File without changes