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 +1 -1
- bcmd/tasks/__init__.py +1 -0
- bcmd/tasks/docs.py +185 -0
- bcmd/tasks/upgrade.py +3 -4
- bcmd/utils/utils.py +9 -0
- {bcmd-0.6.9.dist-info → bcmd-0.6.10.dist-info}/METADATA +2 -1
- {bcmd-0.6.9.dist-info → bcmd-0.6.10.dist-info}/RECORD +10 -8
- {bcmd-0.6.9.dist-info → bcmd-0.6.10.dist-info}/WHEEL +0 -0
- {bcmd-0.6.9.dist-info → bcmd-0.6.10.dist-info}/entry_points.txt +0 -0
- {bcmd-0.6.9.dist-info → bcmd-0.6.10.dist-info}/top_level.txt +0 -0
bcmd/common/func.py
CHANGED
bcmd/tasks/__init__.py
CHANGED
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('
|
|
14
|
+
name: str = typer.Argument('bcmd', help='要更新的包名'),
|
|
15
15
|
):
|
|
16
|
-
'使用
|
|
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bcmd
|
|
3
|
-
Version: 0.6.
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
29
|
-
bcmd-0.6.
|
|
30
|
-
bcmd-0.6.
|
|
31
|
-
bcmd-0.6.
|
|
32
|
-
bcmd-0.6.
|
|
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
|
|
File without changes
|
|
File without changes
|