bcmd 0.5.2__py3-none-any.whl → 0.5.4__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 +19 -19
- bcmd/common/password.py +34 -34
- bcmd/main.py +10 -10
- bcmd/resources/project/.vscode/launch.json +14 -14
- bcmd/resources/project/.vscode/tasks.json +67 -67
- bcmd/tasks/__init__.py +15 -15
- bcmd/tasks/bin.py +104 -104
- bcmd/tasks/code.py +96 -96
- bcmd/tasks/crypto.py +116 -116
- bcmd/tasks/debian.py +78 -78
- bcmd/tasks/download.py +74 -74
- bcmd/tasks/image.py +205 -201
- bcmd/tasks/json.py +25 -25
- bcmd/tasks/lib.py +118 -118
- bcmd/tasks/math.py +97 -97
- bcmd/tasks/mirror.py +46 -46
- bcmd/tasks/project.py +34 -34
- bcmd/tasks/proxy.py +55 -54
- bcmd/tasks/time.py +81 -81
- bcmd/tasks/venv.py +217 -217
- {bcmd-0.5.2.dist-info → bcmd-0.5.4.dist-info}/METADATA +1 -1
- bcmd-0.5.4.dist-info/RECORD +30 -0
- bcmd-0.5.2.dist-info/RECORD +0 -30
- {bcmd-0.5.2.dist-info → bcmd-0.5.4.dist-info}/WHEEL +0 -0
- {bcmd-0.5.2.dist-info → bcmd-0.5.4.dist-info}/entry_points.txt +0 -0
- {bcmd-0.5.2.dist-info → bcmd-0.5.4.dist-info}/top_level.txt +0 -0
bcmd/tasks/lib.py
CHANGED
|
@@ -1,118 +1,118 @@
|
|
|
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 = \[(.*?)\]', 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 = \[(.*?)\]', 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
|
+
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 = \[(.*?)\]', 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 = \[(.*?)\]', 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()
|
bcmd/tasks/math.py
CHANGED
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
from typing import Final
|
|
2
|
-
|
|
3
|
-
import typer
|
|
4
|
-
from beni import bcolor, btask
|
|
5
|
-
from beni.bfunc import Counter, syncCall, toFloat
|
|
6
|
-
from prettytable import PrettyTable
|
|
7
|
-
|
|
8
|
-
app: Final = btask.newSubApp('math 工具集')
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@app.command()
|
|
12
|
-
@syncCall
|
|
13
|
-
async def scale(
|
|
14
|
-
a: float = typer.Argument(..., help='原始数值'),
|
|
15
|
-
b: float = typer.Argument(..., help='原始数值'),
|
|
16
|
-
c: str = typer.Argument(..., help='数值 或 ?'),
|
|
17
|
-
d: str = typer.Argument(..., help='数值 或 ?'),
|
|
18
|
-
):
|
|
19
|
-
'按比例计算数值,例子:beni math scale 1 2 3 ?'
|
|
20
|
-
if not ((c == '?') != (d == '?')):
|
|
21
|
-
return bcolor.printRed('参数C和参数D必须有且仅有一个为?')
|
|
22
|
-
print()
|
|
23
|
-
table = PrettyTable(
|
|
24
|
-
title=bcolor.yellow('按比例计算数值'),
|
|
25
|
-
)
|
|
26
|
-
if c == '?':
|
|
27
|
-
dd = toFloat(d)
|
|
28
|
-
cc = a * dd / b
|
|
29
|
-
table.add_rows([
|
|
30
|
-
['A', a, bcolor.magenta(str(cc)), bcolor.magenta('C')],
|
|
31
|
-
['B', b, dd, 'D'],
|
|
32
|
-
])
|
|
33
|
-
elif d == '?':
|
|
34
|
-
cc = toFloat(c)
|
|
35
|
-
dd = b * cc / a
|
|
36
|
-
table.add_rows([
|
|
37
|
-
['A', a, cc, 'C'],
|
|
38
|
-
['B', b, bcolor.magenta(str(dd)), bcolor.magenta('D')],
|
|
39
|
-
])
|
|
40
|
-
print(table.get_string(header=False))
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@app.command()
|
|
44
|
-
@syncCall
|
|
45
|
-
async def discount(
|
|
46
|
-
values: list[str] = typer.Argument(..., help='每组数据使用#作为分隔符,注意后面的数据不能为0,例:123#500'),
|
|
47
|
-
):
|
|
48
|
-
'计算折扣,例子:beni math discount 123#500 130#550'
|
|
49
|
-
btask.assertTrue(len(values) >= 2, '至少需要提供2组数据用作比较')
|
|
50
|
-
|
|
51
|
-
class Data:
|
|
52
|
-
def __init__(self, value: str):
|
|
53
|
-
try:
|
|
54
|
-
ary = [x.strip() for x in value.strip().split('#')]
|
|
55
|
-
self.a = float(ary[0])
|
|
56
|
-
self.b = float(ary[1])
|
|
57
|
-
self.v = self.a / self.b
|
|
58
|
-
self.discount = 0.0
|
|
59
|
-
except:
|
|
60
|
-
btask.abort(f'数据格式错误', value)
|
|
61
|
-
|
|
62
|
-
datas = [Data(x) for x in values]
|
|
63
|
-
table = PrettyTable(
|
|
64
|
-
title=bcolor.yellow('计算折扣'),
|
|
65
|
-
)
|
|
66
|
-
vAry = [x.v for x in datas]
|
|
67
|
-
minV = min(vAry)
|
|
68
|
-
maxV = max(vAry)
|
|
69
|
-
for data in datas:
|
|
70
|
-
data.discount = -(maxV - data.v) / maxV
|
|
71
|
-
table.add_column(
|
|
72
|
-
'',
|
|
73
|
-
[
|
|
74
|
-
'前数据',
|
|
75
|
-
'后数据',
|
|
76
|
-
'单价',
|
|
77
|
-
'折扣',
|
|
78
|
-
],
|
|
79
|
-
)
|
|
80
|
-
counter = Counter(-1)
|
|
81
|
-
for data in datas:
|
|
82
|
-
colorFunc = bcolor.white
|
|
83
|
-
if data.v == minV:
|
|
84
|
-
colorFunc = bcolor.green
|
|
85
|
-
elif data.v == maxV:
|
|
86
|
-
colorFunc = bcolor.red
|
|
87
|
-
columns = [
|
|
88
|
-
f'{data.a:,}',
|
|
89
|
-
f'{data.b:,}',
|
|
90
|
-
f'{data.v:,.3f}',
|
|
91
|
-
f'{data.discount * 100:+,.3f}%' if data.discount else '',
|
|
92
|
-
]
|
|
93
|
-
table.add_column(
|
|
94
|
-
chr(65 + counter()),
|
|
95
|
-
[colorFunc(x) for x in columns],
|
|
96
|
-
)
|
|
97
|
-
print(table.get_string())
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from beni import bcolor, btask
|
|
5
|
+
from beni.bfunc import Counter, syncCall, toFloat
|
|
6
|
+
from prettytable import PrettyTable
|
|
7
|
+
|
|
8
|
+
app: Final = btask.newSubApp('math 工具集')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command()
|
|
12
|
+
@syncCall
|
|
13
|
+
async def scale(
|
|
14
|
+
a: float = typer.Argument(..., help='原始数值'),
|
|
15
|
+
b: float = typer.Argument(..., help='原始数值'),
|
|
16
|
+
c: str = typer.Argument(..., help='数值 或 ?'),
|
|
17
|
+
d: str = typer.Argument(..., help='数值 或 ?'),
|
|
18
|
+
):
|
|
19
|
+
'按比例计算数值,例子:beni math scale 1 2 3 ?'
|
|
20
|
+
if not ((c == '?') != (d == '?')):
|
|
21
|
+
return bcolor.printRed('参数C和参数D必须有且仅有一个为?')
|
|
22
|
+
print()
|
|
23
|
+
table = PrettyTable(
|
|
24
|
+
title=bcolor.yellow('按比例计算数值'),
|
|
25
|
+
)
|
|
26
|
+
if c == '?':
|
|
27
|
+
dd = toFloat(d)
|
|
28
|
+
cc = a * dd / b
|
|
29
|
+
table.add_rows([
|
|
30
|
+
['A', a, bcolor.magenta(str(cc)), bcolor.magenta('C')],
|
|
31
|
+
['B', b, dd, 'D'],
|
|
32
|
+
])
|
|
33
|
+
elif d == '?':
|
|
34
|
+
cc = toFloat(c)
|
|
35
|
+
dd = b * cc / a
|
|
36
|
+
table.add_rows([
|
|
37
|
+
['A', a, cc, 'C'],
|
|
38
|
+
['B', b, bcolor.magenta(str(dd)), bcolor.magenta('D')],
|
|
39
|
+
])
|
|
40
|
+
print(table.get_string(header=False))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@app.command()
|
|
44
|
+
@syncCall
|
|
45
|
+
async def discount(
|
|
46
|
+
values: list[str] = typer.Argument(..., help='每组数据使用#作为分隔符,注意后面的数据不能为0,例:123#500'),
|
|
47
|
+
):
|
|
48
|
+
'计算折扣,例子:beni math discount 123#500 130#550'
|
|
49
|
+
btask.assertTrue(len(values) >= 2, '至少需要提供2组数据用作比较')
|
|
50
|
+
|
|
51
|
+
class Data:
|
|
52
|
+
def __init__(self, value: str):
|
|
53
|
+
try:
|
|
54
|
+
ary = [x.strip() for x in value.strip().split('#')]
|
|
55
|
+
self.a = float(ary[0])
|
|
56
|
+
self.b = float(ary[1])
|
|
57
|
+
self.v = self.a / self.b
|
|
58
|
+
self.discount = 0.0
|
|
59
|
+
except:
|
|
60
|
+
btask.abort(f'数据格式错误', value)
|
|
61
|
+
|
|
62
|
+
datas = [Data(x) for x in values]
|
|
63
|
+
table = PrettyTable(
|
|
64
|
+
title=bcolor.yellow('计算折扣'),
|
|
65
|
+
)
|
|
66
|
+
vAry = [x.v for x in datas]
|
|
67
|
+
minV = min(vAry)
|
|
68
|
+
maxV = max(vAry)
|
|
69
|
+
for data in datas:
|
|
70
|
+
data.discount = -(maxV - data.v) / maxV
|
|
71
|
+
table.add_column(
|
|
72
|
+
'',
|
|
73
|
+
[
|
|
74
|
+
'前数据',
|
|
75
|
+
'后数据',
|
|
76
|
+
'单价',
|
|
77
|
+
'折扣',
|
|
78
|
+
],
|
|
79
|
+
)
|
|
80
|
+
counter = Counter(-1)
|
|
81
|
+
for data in datas:
|
|
82
|
+
colorFunc = bcolor.white
|
|
83
|
+
if data.v == minV:
|
|
84
|
+
colorFunc = bcolor.green
|
|
85
|
+
elif data.v == maxV:
|
|
86
|
+
colorFunc = bcolor.red
|
|
87
|
+
columns = [
|
|
88
|
+
f'{data.a:,}',
|
|
89
|
+
f'{data.b:,}',
|
|
90
|
+
f'{data.v:,.3f}',
|
|
91
|
+
f'{data.discount * 100:+,.3f}%' if data.discount else '',
|
|
92
|
+
]
|
|
93
|
+
table.add_column(
|
|
94
|
+
chr(65 + counter()),
|
|
95
|
+
[colorFunc(x) for x in columns],
|
|
96
|
+
)
|
|
97
|
+
print(table.get_string())
|
bcmd/tasks/mirror.py
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import platform
|
|
4
|
-
from typing import Final
|
|
5
|
-
|
|
6
|
-
import typer
|
|
7
|
-
from beni import bcolor, bfile, bpath, btask
|
|
8
|
-
from beni.bfunc import syncCall
|
|
9
|
-
|
|
10
|
-
app: Final = btask.app
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@app.command()
|
|
14
|
-
@syncCall
|
|
15
|
-
async def mirror(
|
|
16
|
-
disabled: bool = typer.Option(False, '--disabled', '-d', help="是否禁用"),
|
|
17
|
-
):
|
|
18
|
-
'设置镜像'
|
|
19
|
-
|
|
20
|
-
# 根据不同的系统平台
|
|
21
|
-
match platform.system():
|
|
22
|
-
case 'Windows':
|
|
23
|
-
file = bpath.user('pip/pip.ini')
|
|
24
|
-
case 'Linux':
|
|
25
|
-
file = bpath.user('.pip/pip.conf')
|
|
26
|
-
case _:
|
|
27
|
-
btask.abort('暂时不支持该平台', platform.system())
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
if disabled:
|
|
31
|
-
bpath.remove(file)
|
|
32
|
-
bcolor.printRed('删除文件', file)
|
|
33
|
-
else:
|
|
34
|
-
content = _content.strip()
|
|
35
|
-
await bfile.writeText(file, content)
|
|
36
|
-
bcolor.printYellow(file)
|
|
37
|
-
bcolor.printMagenta(content)
|
|
38
|
-
bcolor.printGreen('OK')
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# ------------------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
_content = '''
|
|
44
|
-
[global]
|
|
45
|
-
index-url = https://mirrors.aliyun.com/pypi/simple
|
|
46
|
-
'''
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import platform
|
|
4
|
+
from typing import Final
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from beni import bcolor, bfile, bpath, btask
|
|
8
|
+
from beni.bfunc import syncCall
|
|
9
|
+
|
|
10
|
+
app: Final = btask.app
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
@syncCall
|
|
15
|
+
async def mirror(
|
|
16
|
+
disabled: bool = typer.Option(False, '--disabled', '-d', help="是否禁用"),
|
|
17
|
+
):
|
|
18
|
+
'设置镜像'
|
|
19
|
+
|
|
20
|
+
# 根据不同的系统平台
|
|
21
|
+
match platform.system():
|
|
22
|
+
case 'Windows':
|
|
23
|
+
file = bpath.user('pip/pip.ini')
|
|
24
|
+
case 'Linux':
|
|
25
|
+
file = bpath.user('.pip/pip.conf')
|
|
26
|
+
case _:
|
|
27
|
+
btask.abort('暂时不支持该平台', platform.system())
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
if disabled:
|
|
31
|
+
bpath.remove(file)
|
|
32
|
+
bcolor.printRed('删除文件', file)
|
|
33
|
+
else:
|
|
34
|
+
content = _content.strip()
|
|
35
|
+
await bfile.writeText(file, content)
|
|
36
|
+
bcolor.printYellow(file)
|
|
37
|
+
bcolor.printMagenta(content)
|
|
38
|
+
bcolor.printGreen('OK')
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ------------------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
_content = '''
|
|
44
|
+
[global]
|
|
45
|
+
index-url = https://mirrors.aliyun.com/pypi/simple
|
|
46
|
+
'''
|
bcmd/tasks/project.py
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Final
|
|
3
|
-
|
|
4
|
-
import typer
|
|
5
|
-
from beni import bcolor, binput, bpath, btask
|
|
6
|
-
from beni.bfunc import syncCall
|
|
7
|
-
|
|
8
|
-
from ..common.func import useResources
|
|
9
|
-
from .venv import add as venvAdd
|
|
10
|
-
|
|
11
|
-
app: Final = btask.app
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@app.command('project')
|
|
15
|
-
@syncCall
|
|
16
|
-
async def _(
|
|
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
|
-
venvAdd(['benimang'], path)
|
|
33
|
-
with useResources('project') as sourceProjectPath:
|
|
34
|
-
bpath.copyOverwrite(sourceProjectPath, path)
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Final
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from beni import bcolor, binput, bpath, btask
|
|
6
|
+
from beni.bfunc import syncCall
|
|
7
|
+
|
|
8
|
+
from ..common.func import useResources
|
|
9
|
+
from .venv import add as venvAdd
|
|
10
|
+
|
|
11
|
+
app: Final = btask.app
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command('project')
|
|
15
|
+
@syncCall
|
|
16
|
+
async def _(
|
|
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
|
+
venvAdd(['benimang==now'], path)
|
|
33
|
+
with useResources('project') as sourceProjectPath:
|
|
34
|
+
bpath.copyOverwrite(sourceProjectPath, path)
|