bcmd 0.5.17__tar.gz → 0.6.0__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.
Potentially problematic release.
This version of bcmd might be problematic. Click here for more details.
- {bcmd-0.5.17 → bcmd-0.6.0}/PKG-INFO +7 -1
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/__init__.py +0 -2
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/image.py +2 -2
- bcmd-0.6.0/bcmd/tasks/lib.py +59 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/upgrade.py +7 -3
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/PKG-INFO +7 -1
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/SOURCES.txt +0 -2
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/requires.txt +7 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/pyproject.toml +16 -7
- bcmd-0.5.17/bcmd/tasks/lib.py +0 -118
- bcmd-0.5.17/bcmd/tasks/project.py +0 -59
- bcmd-0.5.17/bcmd/tasks/venv.py +0 -227
- {bcmd-0.5.17 → bcmd-0.6.0}/MANIFEST.in +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/README.md +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/__init__.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/common/__init__.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/common/func.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/common/password.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/main.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/resources/project/.gitignore +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/resources/project/.vscode/launch.json +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/resources/project/.vscode/settings.json +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/resources/project/.vscode/tasks.json +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/resources/project/main.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/bin.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/code.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/crypto.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/debian.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/download.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/json.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/math.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/mirror.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/pdf.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/proxy.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/time.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd/tasks/wasabi.py +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/dependency_links.txt +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/entry_points.txt +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/bcmd.egg-info/top_level.txt +0 -0
- {bcmd-0.5.17 → bcmd-0.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bcmd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Commands for Beni
|
|
5
5
|
Author-email: Beni Mang <benimang@126.com>
|
|
6
6
|
Maintainer-email: Beni Mang <benimang@126.com>
|
|
@@ -17,3 +17,9 @@ Requires-Dist: pymupdf
|
|
|
17
17
|
Requires-Dist: qiniu
|
|
18
18
|
Requires-Dist: twine
|
|
19
19
|
Requires-Dist: typer
|
|
20
|
+
Provides-Extra: full
|
|
21
|
+
Requires-Dist: img2pdf; extra == "full"
|
|
22
|
+
Requires-Dist: pytest; extra == "full"
|
|
23
|
+
Requires-Dist: pytest-asyncio; extra == "full"
|
|
24
|
+
Requires-Dist: pytest-order; extra == "full"
|
|
25
|
+
Requires-Dist: setuptools; extra == "full"
|
|
@@ -285,14 +285,14 @@ async def merge(
|
|
|
285
285
|
# 修改保存参数为 WebP 格式
|
|
286
286
|
merged_image.save(
|
|
287
287
|
output_path,
|
|
288
|
-
format='
|
|
288
|
+
format='JPEG',
|
|
289
289
|
quality=80, # 质量参数(0-100),推荐 80-90 之间
|
|
290
290
|
method=6, # 压缩方法(0-6),6 为最佳压缩
|
|
291
291
|
lossless=False, # 不使用无损压缩(更小的文件体积)
|
|
292
292
|
)
|
|
293
293
|
|
|
294
294
|
image_files = [x for x in bpath.listFile(path) if x.suffix in ('.png', '.jpg', '.jpeg', '.webp', '.bmp')]
|
|
295
|
-
output_image = path / f'merge_{path.name}.
|
|
295
|
+
output_image = path / f'merge_{path.name}.jpg' # 修改文件扩展名为 webp
|
|
296
296
|
if output_image in image_files:
|
|
297
297
|
if not force:
|
|
298
298
|
print(output_image)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from beni import bcolor, bfile, bpath, brun, btask
|
|
7
|
+
from beni.bfunc import syncCall
|
|
8
|
+
|
|
9
|
+
from ..common import password
|
|
10
|
+
|
|
11
|
+
app: Final = btask.newSubApp('lib 工具')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command()
|
|
15
|
+
@syncCall
|
|
16
|
+
async def update_version(
|
|
17
|
+
path: Path = typer.Argument(Path.cwd(), help='workspace 路径'),
|
|
18
|
+
isNotCommit: bool = typer.Option(False, '--no-commit', '-d', help='是否提交git'),
|
|
19
|
+
):
|
|
20
|
+
'修改 pyproject.toml 版本号'
|
|
21
|
+
file = path / 'pyproject.toml'
|
|
22
|
+
btask.assertTrue(file.is_file(), '文件不存在', file)
|
|
23
|
+
data = await bfile.readToml(file)
|
|
24
|
+
version = data['project']['version']
|
|
25
|
+
versionList = [int(x) for x in version.split('.')]
|
|
26
|
+
versionList[-1] += 1
|
|
27
|
+
newVersion = '.'.join([str(x) for x in versionList])
|
|
28
|
+
content = await bfile.readText(file)
|
|
29
|
+
if f"version = '{version}'" in content:
|
|
30
|
+
content = content.replace(f"version = '{version}'", f"version = '{newVersion}'")
|
|
31
|
+
elif f'version = "{version}"' in content:
|
|
32
|
+
content = content.replace(f'version = "{version}"', f'version = "{newVersion}"')
|
|
33
|
+
else:
|
|
34
|
+
raise Exception('版本号修改失败,先检查文件中定义的版本号格式是否正常')
|
|
35
|
+
await bfile.writeText(file, content)
|
|
36
|
+
bcolor.printCyan(newVersion)
|
|
37
|
+
if not isNotCommit:
|
|
38
|
+
msg = f'更新版本号 {newVersion}'
|
|
39
|
+
os.system(
|
|
40
|
+
rf'TortoiseGitProc.exe /command:commit /path:{file} /logmsg:"{msg}"'
|
|
41
|
+
)
|
|
42
|
+
bcolor.printGreen('OK')
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.command()
|
|
46
|
+
@syncCall
|
|
47
|
+
async def build(
|
|
48
|
+
path: Path = typer.Argument(Path.cwd(), help='workspace 路径'),
|
|
49
|
+
isKeepBuildFiles: bool = typer.Option(False, '--keep-build-files', '-k', help='是否保留构建文件'),
|
|
50
|
+
):
|
|
51
|
+
'发布项目'
|
|
52
|
+
user, pwd = await password.getPypi()
|
|
53
|
+
bpath.remove(path / 'dist')
|
|
54
|
+
bpath.remove(
|
|
55
|
+
*list(path.glob('*.egg-info'))
|
|
56
|
+
)
|
|
57
|
+
with bpath.changePath(path):
|
|
58
|
+
await brun.run(f'uv build')
|
|
59
|
+
await brun.run(f'uv publish -u {user} -p {pwd}')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Final
|
|
2
2
|
|
|
3
3
|
import pyperclip
|
|
4
|
+
import typer
|
|
4
5
|
from beni import bcolor, btask
|
|
5
6
|
from beni.bfunc import syncCall
|
|
6
7
|
|
|
@@ -9,9 +10,12 @@ app: Final = btask.app
|
|
|
9
10
|
|
|
10
11
|
@app.command()
|
|
11
12
|
@syncCall
|
|
12
|
-
async def upgrade(
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
async def upgrade(
|
|
14
|
+
name: str = typer.Argument('bcmd', help='要更新的包名'),
|
|
15
|
+
):
|
|
16
|
+
'使用 pipx 官方源更新指定包到最新版本'
|
|
17
|
+
|
|
18
|
+
cmd = f'pipx upgrade {name} -i https://pypi.org/simple'
|
|
15
19
|
pyperclip.copy(cmd + '\n')
|
|
16
20
|
bcolor.printGreen(cmd)
|
|
17
21
|
bcolor.printGreen('已复制到剪贴板(需要手动执行)')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bcmd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Commands for Beni
|
|
5
5
|
Author-email: Beni Mang <benimang@126.com>
|
|
6
6
|
Maintainer-email: Beni Mang <benimang@126.com>
|
|
@@ -17,3 +17,9 @@ Requires-Dist: pymupdf
|
|
|
17
17
|
Requires-Dist: qiniu
|
|
18
18
|
Requires-Dist: twine
|
|
19
19
|
Requires-Dist: typer
|
|
20
|
+
Provides-Extra: full
|
|
21
|
+
Requires-Dist: img2pdf; extra == "full"
|
|
22
|
+
Requires-Dist: pytest; extra == "full"
|
|
23
|
+
Requires-Dist: pytest-asyncio; extra == "full"
|
|
24
|
+
Requires-Dist: pytest-order; extra == "full"
|
|
25
|
+
Requires-Dist: setuptools; extra == "full"
|
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = 'bcmd'
|
|
6
|
-
version = '0.
|
|
6
|
+
version = '0.6.0'
|
|
7
7
|
description = 'Commands for Beni'
|
|
8
8
|
requires-python = '>=3.10'
|
|
9
9
|
keywords = ['benimang', 'beni', 'bcmd']
|
|
10
10
|
authors = [{ name = 'Beni Mang', email = 'benimang@126.com' }]
|
|
11
11
|
maintainers = [{ name = 'Beni Mang', email = 'benimang@126.com' }]
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
dependencies = [
|
|
15
14
|
'benimang==0.7.14',
|
|
16
15
|
'build',
|
|
@@ -23,12 +22,22 @@ dependencies = [
|
|
|
23
22
|
'qiniu',
|
|
24
23
|
'twine',
|
|
25
24
|
'typer',
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
full = [
|
|
29
|
+
'img2pdf',
|
|
30
|
+
'pytest',
|
|
31
|
+
'pytest-asyncio',
|
|
32
|
+
'pytest-order',
|
|
33
|
+
'setuptools',
|
|
31
34
|
]
|
|
32
35
|
|
|
33
36
|
[project.scripts]
|
|
34
37
|
beni = 'bcmd.main:run'
|
|
38
|
+
|
|
39
|
+
# 使用默认镜像地址
|
|
40
|
+
[[tool.uv.index]]
|
|
41
|
+
url = "https://mirrors.aliyun.com/pypi/simple"
|
|
42
|
+
default = true
|
|
43
|
+
|
bcmd-0.5.17/bcmd/tasks/lib.py
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import re
|
|
3
|
-
from contextlib import contextmanager
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Final
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
from beni import bcolor, bfile, bpath, btask
|
|
9
|
-
from beni.bfunc import syncCall, textToAry
|
|
10
|
-
|
|
11
|
-
from ..common import password
|
|
12
|
-
from .venv import getPackageList
|
|
13
|
-
|
|
14
|
-
app: Final = btask.newSubApp('lib 工具')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@app.command()
|
|
18
|
-
@syncCall
|
|
19
|
-
async def tidy_dependencies(
|
|
20
|
-
workspace_path: Path = typer.Argument(Path.cwd(), help='workspace 路径'),
|
|
21
|
-
isWithVersion: bool = typer.Option(False, '--with-version', help='是否带版本号')
|
|
22
|
-
):
|
|
23
|
-
'整理 pyproject.toml 里面的 dependencies'
|
|
24
|
-
pyprojectTomlFile = workspace_path / 'pyproject.toml'
|
|
25
|
-
btask.assertTrue(pyprojectTomlFile.is_file(), 'pyproject.toml 不存在', pyprojectTomlFile)
|
|
26
|
-
venvFile = bpath.get(workspace_path, f'.venv')
|
|
27
|
-
btask.assertTrue(venvFile.is_file(), '.venv 不存在', venvFile)
|
|
28
|
-
basePackages, lockPackages = await getPackageList(venvFile)
|
|
29
|
-
libAry = lockPackages if isWithVersion else basePackages
|
|
30
|
-
oldContent = await bfile.readText(pyprojectTomlFile)
|
|
31
|
-
ignoreLibAry = _getIgnoreLibAry(oldContent)
|
|
32
|
-
ignoreLibAry = sorted(list(set(ignoreLibAry) & set(libAry)))
|
|
33
|
-
libAry = sorted(list(set(libAry) - set(ignoreLibAry)))
|
|
34
|
-
replaceContent = '\n'.join([f" '{x}'," for x in libAry]) + '\n' + '\n'.join([f" # '{x}'," for x in ignoreLibAry])
|
|
35
|
-
newContent = re.sub(r'dependencies = \[(.*?)\n\]', f"dependencies = [\n{replaceContent}\n]", oldContent, 0, re.DOTALL)
|
|
36
|
-
if oldContent != newContent:
|
|
37
|
-
await bfile.writeText(pyprojectTomlFile, newContent)
|
|
38
|
-
bcolor.printYellow(pyprojectTomlFile)
|
|
39
|
-
bcolor.printMagenta(newContent)
|
|
40
|
-
return True
|
|
41
|
-
else:
|
|
42
|
-
bcolor.printGreen('无需修改依赖')
|
|
43
|
-
return False
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@app.command()
|
|
47
|
-
@syncCall
|
|
48
|
-
async def update_version(
|
|
49
|
-
path: Path = typer.Argument(Path.cwd(), help='workspace 路径'),
|
|
50
|
-
isNotCommit: bool = typer.Option(False, '--no-commit', '-d', help='是否提交git'),
|
|
51
|
-
):
|
|
52
|
-
'修改 pyproject.toml 版本号'
|
|
53
|
-
file = path / 'pyproject.toml'
|
|
54
|
-
btask.assertTrue(file.is_file(), '文件不存在', file)
|
|
55
|
-
data = await bfile.readToml(file)
|
|
56
|
-
version = data['project']['version']
|
|
57
|
-
versionList = [int(x) for x in version.split('.')]
|
|
58
|
-
versionList[-1] += 1
|
|
59
|
-
newVersion = '.'.join([str(x) for x in versionList])
|
|
60
|
-
content = await bfile.readText(file)
|
|
61
|
-
if f"version = '{version}'" in content:
|
|
62
|
-
content = content.replace(f"version = '{version}'", f"version = '{newVersion}'")
|
|
63
|
-
elif f'version = "{version}"' in content:
|
|
64
|
-
content = content.replace(f'version = "{version}"', f'version = "{newVersion}"')
|
|
65
|
-
else:
|
|
66
|
-
raise Exception('版本号修改失败,先检查文件中定义的版本号格式是否正常')
|
|
67
|
-
await bfile.writeText(file, content)
|
|
68
|
-
bcolor.printCyan(newVersion)
|
|
69
|
-
if not isNotCommit:
|
|
70
|
-
msg = f'更新版本号 {newVersion}'
|
|
71
|
-
os.system(
|
|
72
|
-
rf'TortoiseGitProc.exe /command:commit /path:{file} /logmsg:"{msg}"'
|
|
73
|
-
)
|
|
74
|
-
bcolor.printGreen('OK')
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@app.command()
|
|
78
|
-
@syncCall
|
|
79
|
-
async def build(
|
|
80
|
-
path: Path = typer.Argument(Path.cwd(), help='workspace 路径'),
|
|
81
|
-
isKeepBuildFiles: bool = typer.Option(False, '--keep-build-files', '-k', help='是否保留构建文件'),
|
|
82
|
-
):
|
|
83
|
-
'发布项目'
|
|
84
|
-
u, p = await password.getPypi()
|
|
85
|
-
with _useBuildPath(path, isKeepBuildFiles):
|
|
86
|
-
scriptPath = (path / './venv/Scripts')
|
|
87
|
-
os.system(f'{scriptPath / "python.exe"} -m build')
|
|
88
|
-
os.system(f'{scriptPath / "twine.exe"} upload dist/* -u {u} -p {p}')
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# ------------------------------------------------------------------------------------
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def _getIgnoreLibAry(content: str) -> list[str]:
|
|
95
|
-
'获取pyproject.toml中屏蔽的第三方库'
|
|
96
|
-
content = re.findall(r'dependencies = \[(.*?)\n\]', content, re.DOTALL)[0]
|
|
97
|
-
ary = textToAry(content)
|
|
98
|
-
return sorted([x[1:].replace('"', '').replace("'", '').replace(',', '').strip() for x in filter(lambda x: x.startswith('#'), ary)])
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@contextmanager
|
|
102
|
-
def _useBuildPath(workspacePath: Path, isKeepBuildFiles: bool):
|
|
103
|
-
'整理构建目录,先清空不必要的输出目录,结束后再判断是否需要再清空一次'
|
|
104
|
-
|
|
105
|
-
def removeUnusedPath():
|
|
106
|
-
bpath.remove(workspacePath / 'dist')
|
|
107
|
-
paths = bpath.listDir(workspacePath)
|
|
108
|
-
for x in paths:
|
|
109
|
-
if x.name.endswith('.egg-info'):
|
|
110
|
-
bpath.remove(x)
|
|
111
|
-
|
|
112
|
-
try:
|
|
113
|
-
with bpath.changePath(workspacePath):
|
|
114
|
-
removeUnusedPath()
|
|
115
|
-
yield
|
|
116
|
-
finally:
|
|
117
|
-
if not isKeepBuildFiles:
|
|
118
|
-
removeUnusedPath()
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Final
|
|
3
|
-
|
|
4
|
-
import typer
|
|
5
|
-
from beni import bcolor, binput, bpath, brun, btask
|
|
6
|
-
from beni.bfunc import syncCall
|
|
7
|
-
|
|
8
|
-
from ..common.func import useResources
|
|
9
|
-
from . import venv
|
|
10
|
-
|
|
11
|
-
app: Final = btask.newSubApp('项目相关')
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@app.command()
|
|
15
|
-
@syncCall
|
|
16
|
-
async def create_py(
|
|
17
|
-
path: Path = typer.Option(Path.cwd(), '--path', help='workspace 路径'),
|
|
18
|
-
):
|
|
19
|
-
'生成新项目'
|
|
20
|
-
|
|
21
|
-
# 检查目标路径是否合法
|
|
22
|
-
if path.exists():
|
|
23
|
-
if not path.is_dir():
|
|
24
|
-
bcolor.printRed('目标路径不是一个目录', path)
|
|
25
|
-
return
|
|
26
|
-
elif list(bpath.get(path).glob('*')):
|
|
27
|
-
bcolor.printRed('目标路径不是空目录', path)
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
bcolor.printYellow(path)
|
|
31
|
-
await binput.confirm('即将在此路径生成新项目,是否继续?')
|
|
32
|
-
venv.add(['benimang==now'], path)
|
|
33
|
-
with useResources('project') as sourceProjectPath:
|
|
34
|
-
bpath.copyOverwrite(sourceProjectPath, path)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@app.command()
|
|
38
|
-
@syncCall
|
|
39
|
-
async def install(
|
|
40
|
-
path: Path = typer.Option(Path.cwd(), '--path', help='初始化项目的路径'),
|
|
41
|
-
deep: int = typer.Option(3, '--deep', help='探索路径深度(默认:1)'),
|
|
42
|
-
):
|
|
43
|
-
'初始化项目(python项目执行beni venv install-lock / nodejs项目执行 pnpm install)'
|
|
44
|
-
|
|
45
|
-
async def checkPath(currentPath: Path, currentDeep: int):
|
|
46
|
-
for file in bpath.listFile(currentPath):
|
|
47
|
-
if file.name == '.venv':
|
|
48
|
-
with bpath.changePath(file.parent):
|
|
49
|
-
await brun.run('beni venv install-lock', isPrint=True)
|
|
50
|
-
return
|
|
51
|
-
elif file.name == 'package.json':
|
|
52
|
-
with bpath.changePath(file.parent):
|
|
53
|
-
await brun.run('pnpm install', isPrint=True)
|
|
54
|
-
return
|
|
55
|
-
if currentDeep < deep:
|
|
56
|
-
for folder in bpath.listPath(currentPath):
|
|
57
|
-
await checkPath(folder, currentDeep + 1)
|
|
58
|
-
|
|
59
|
-
await checkPath(path, 0)
|
bcmd-0.5.17/bcmd/tasks/venv.py
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import platform
|
|
3
|
-
import re
|
|
4
|
-
import sys
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Final
|
|
7
|
-
|
|
8
|
-
import typer
|
|
9
|
-
from beni import bcolor, bexecute, bfile, bhttp, bpath, brun, btask
|
|
10
|
-
from beni.bfunc import syncCall
|
|
11
|
-
from beni.btype import Null
|
|
12
|
-
from prettytable import PrettyTable
|
|
13
|
-
|
|
14
|
-
from ..common.func import checkFileOrNotExists, checkPathOrNotExists
|
|
15
|
-
|
|
16
|
-
app: Final = btask.newSubApp('venv 相关')
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@app.command()
|
|
20
|
-
@syncCall
|
|
21
|
-
async def add(
|
|
22
|
-
packages: list[str] = typer.Argument(None),
|
|
23
|
-
path: Path = typer.Option(None, '--path', help='指定路径,默认当前目录'),
|
|
24
|
-
isOfficial: bool = typer.Option(False, '--official', help='是否使用官方地址安装(https://pypi.org/simple)'),
|
|
25
|
-
):
|
|
26
|
-
'添加指定库'
|
|
27
|
-
await _venv(
|
|
28
|
-
packages,
|
|
29
|
-
path=path,
|
|
30
|
-
isOfficial=isOfficial,
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@app.command()
|
|
35
|
-
@syncCall
|
|
36
|
-
async def install_benimang(
|
|
37
|
-
path: Path = typer.Option(None, '--path', help='指定路径,默认当前目录'),
|
|
38
|
-
):
|
|
39
|
-
'更新 benimang 库,强制使用官方源'
|
|
40
|
-
path = path or Path(os.getcwd())
|
|
41
|
-
pip = getPipFile(path)
|
|
42
|
-
await brun.run(f'{pip} install benimang -U -i https://pypi.org/simple', isPrint=True)
|
|
43
|
-
await _venv(
|
|
44
|
-
['benimang==now'],
|
|
45
|
-
path=path,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@app.command()
|
|
50
|
-
@syncCall
|
|
51
|
-
async def install_base(
|
|
52
|
-
path: Path = typer.Option(None, '--path', help='指定路径,默认当前目录'),
|
|
53
|
-
isOfficial: bool = typer.Option(False, '--official', help='是否使用官方地址安装(https://pypi.org/simple)'),
|
|
54
|
-
isCleanup: bool = typer.Option(False, '--cleanup', help='是否清空venv目录后重新安装'),
|
|
55
|
-
):
|
|
56
|
-
'安装基础库'
|
|
57
|
-
await _venv(
|
|
58
|
-
path=path,
|
|
59
|
-
isOfficial=isOfficial,
|
|
60
|
-
isUseBase=True,
|
|
61
|
-
isCleanup=isCleanup,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@app.command()
|
|
66
|
-
@syncCall
|
|
67
|
-
async def install_lock(
|
|
68
|
-
path: Path = typer.Option(None, '--path', help='指定路径,默认当前目录'),
|
|
69
|
-
isOfficial: bool = typer.Option(False, '--official', help='是否使用官方地址安装(https://pypi.org/simple)'),
|
|
70
|
-
isCleanup: bool = typer.Option(False, '--cleanup', help='是否清空venv目录后重新安装'),
|
|
71
|
-
):
|
|
72
|
-
'安装指定版本的库'
|
|
73
|
-
await _venv(
|
|
74
|
-
path=path,
|
|
75
|
-
isOfficial=isOfficial,
|
|
76
|
-
isUseLock=True,
|
|
77
|
-
isCleanup=isCleanup,
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# ------------------------------------------------------------------------------------
|
|
82
|
-
|
|
83
|
-
async def _venv(
|
|
84
|
-
packages: list[str] = [],
|
|
85
|
-
*,
|
|
86
|
-
path: Path = Null,
|
|
87
|
-
isOfficial: bool = False,
|
|
88
|
-
isUseBase: bool = False,
|
|
89
|
-
isUseLock: bool = False,
|
|
90
|
-
isCleanup: bool = False,
|
|
91
|
-
):
|
|
92
|
-
'python 虚拟环境配置'
|
|
93
|
-
btask.assertTrue(not (isUseBase == isUseLock == True), '2个选项只能选择其中一个 --use-base / --use-lock')
|
|
94
|
-
path = path or Path(os.getcwd())
|
|
95
|
-
venvPath = getVenvPath(path)
|
|
96
|
-
checkPathOrNotExists(venvPath)
|
|
97
|
-
venvFile = bpath.get(path, '.venv')
|
|
98
|
-
checkFileOrNotExists(venvFile)
|
|
99
|
-
if isCleanup:
|
|
100
|
-
bpath.remove(venvPath)
|
|
101
|
-
btask.assertTrue(not venvPath.exists(), f'无法删除 venv 目录 {venvPath}')
|
|
102
|
-
packages = packages or []
|
|
103
|
-
for i in range(len(packages)):
|
|
104
|
-
package = packages[i]
|
|
105
|
-
if package.endswith('==now'):
|
|
106
|
-
ary = package.split('==')
|
|
107
|
-
packages[i] = f'{ary[0]}=={await _getPackageLatestVersion(ary[0])}'
|
|
108
|
-
if not venvPath.exists():
|
|
109
|
-
await bexecute.run(f'python -m venv {venvPath}')
|
|
110
|
-
if not venvFile.exists():
|
|
111
|
-
await bfile.writeText(venvFile, '')
|
|
112
|
-
basePackages, lockPackages = await getPackageList(venvFile)
|
|
113
|
-
if isUseBase:
|
|
114
|
-
installPackages = _mergePackageList(basePackages, packages)
|
|
115
|
-
elif isUseLock:
|
|
116
|
-
installPackages = _mergePackageList(lockPackages, packages)
|
|
117
|
-
else:
|
|
118
|
-
installPackages = _mergePackageList(lockPackages or basePackages, packages)
|
|
119
|
-
installPackages = sorted(list(set(installPackages)))
|
|
120
|
-
pip = getPipFile(path)
|
|
121
|
-
await _pipInstall(pip, installPackages, isOfficial)
|
|
122
|
-
with bpath.useTempFile() as tempFile:
|
|
123
|
-
await bexecute.run(f'{pip} freeze > {tempFile}')
|
|
124
|
-
basePackages = _mergePackageList(basePackages, packages)
|
|
125
|
-
lockPackages = (await bfile.readText(tempFile)).replace('\r\n', '\n').strip().split('\n')
|
|
126
|
-
await updatePackageList(venvFile, basePackages, lockPackages)
|
|
127
|
-
bcolor.printGreen('OK')
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
async def _pipInstall(pip: Path, installPackages: list[str], disabled_mirror: bool):
|
|
131
|
-
python = pip.with_stem('python')
|
|
132
|
-
btask.assertTrue(python.is_file(), f'无法找到指定文件 {python}')
|
|
133
|
-
btask.assertTrue(pip.is_file(), f'无法找到指定文件 {pip}')
|
|
134
|
-
indexUrl = '-i https://pypi.org/simple' if disabled_mirror else ''
|
|
135
|
-
with bpath.useTempFile() as file:
|
|
136
|
-
await bfile.writeText(file, '\n'.join(installPackages))
|
|
137
|
-
table = PrettyTable()
|
|
138
|
-
table.add_column(
|
|
139
|
-
bcolor.yellow('#'),
|
|
140
|
-
[x + 1 for x in range(len(installPackages))],
|
|
141
|
-
)
|
|
142
|
-
table.add_column(
|
|
143
|
-
bcolor.yellow('安装库'),
|
|
144
|
-
[x for x in installPackages],
|
|
145
|
-
'l',
|
|
146
|
-
)
|
|
147
|
-
print(table.get_string())
|
|
148
|
-
|
|
149
|
-
btask.assertTrue(
|
|
150
|
-
not await bexecute.run(f'{python} -m pip install --upgrade pip {indexUrl}'),
|
|
151
|
-
'更新 pip 失败',
|
|
152
|
-
)
|
|
153
|
-
btask.assertTrue(
|
|
154
|
-
not await bexecute.run(f'{pip} install -r {file} {indexUrl}'),
|
|
155
|
-
'执行失败',
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
async def _getPackageDict(venvFile: Path):
|
|
160
|
-
content = await bfile.readText(venvFile)
|
|
161
|
-
pattern = r'\[\[ (.*?) \]\]\n(.*?)(?=\n\[\[|\Z)'
|
|
162
|
-
matches: list[tuple[str, str]] = re.findall(pattern, content.strip(), re.DOTALL)
|
|
163
|
-
return {match[0]: [line.strip() for line in match[1].strip().split('\n') if line.strip()] for match in matches}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
_baseName: Final[str] = 'venv'
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def _getLockName():
|
|
170
|
-
systemName = platform.system()
|
|
171
|
-
return f'{_baseName}-{systemName}'
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
async def getPackageList(venvFile: Path):
|
|
175
|
-
result = await _getPackageDict(venvFile)
|
|
176
|
-
lockName = _getLockName()
|
|
177
|
-
return result.get(_baseName, []), result.get(lockName, [])
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
async def updatePackageList(venvFile: Path, packages: list[str], lockPackages: list[str]):
|
|
181
|
-
packageDict = await _getPackageDict(venvFile)
|
|
182
|
-
lockName = _getLockName()
|
|
183
|
-
packages.sort(key=lambda x: x.lower())
|
|
184
|
-
lockPackages.sort(key=lambda x: x.lower())
|
|
185
|
-
packageDict[_baseName] = packages
|
|
186
|
-
packageDict[lockName] = lockPackages
|
|
187
|
-
content = '\n\n\n'.join([f'\n[[ {key} ]]\n{'\n'.join(value)}' for key, value in packageDict.items()]).strip()
|
|
188
|
-
await bfile.writeText(venvFile, content)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
async def _getPackageLatestVersion(package: str):
|
|
192
|
-
'获取指定包的最新版本'
|
|
193
|
-
data = await bhttp.getJson(
|
|
194
|
-
f'https://pypi.org/pypi/{package}/json'
|
|
195
|
-
)
|
|
196
|
-
return data['info']['version']
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _mergePackageList(basePackages: list[str], addPackages: list[str]):
|
|
200
|
-
basePackagesDict = {_getPackageName(x): x for x in basePackages}
|
|
201
|
-
addPackagesDict = {_getPackageName(x): x for x in addPackages}
|
|
202
|
-
packagesDict = basePackagesDict | addPackagesDict
|
|
203
|
-
return sorted([x for x in packagesDict.values()])
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def _getPackageName(package: str):
|
|
207
|
-
if '==' in package:
|
|
208
|
-
package = package.split('==')[0]
|
|
209
|
-
elif '>' in package:
|
|
210
|
-
package = package.split('>')[0]
|
|
211
|
-
elif '<' in package:
|
|
212
|
-
package = package.split('<')[0]
|
|
213
|
-
package = package.strip()
|
|
214
|
-
if package.startswith('#'):
|
|
215
|
-
package = package.replace('#', '', 1).strip()
|
|
216
|
-
return package
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def getVenvPath(path: Path):
|
|
220
|
-
return bpath.get(path, 'venv')
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def getPipFile(path: Path):
|
|
224
|
-
if sys.platform.startswith('win'):
|
|
225
|
-
return bpath.get(getVenvPath(path), 'Scripts/pip.exe')
|
|
226
|
-
else:
|
|
227
|
-
return bpath.get(getVenvPath(path), 'bin/pip')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|