bcmd 0.2.8__py3-none-any.whl → 0.4.6__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 ADDED
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+
3
+ from beni import btask
4
+
5
+
6
+ def checkFileOrNotExists(file: Path):
7
+ btask.check(file.is_file() or not file.exists(), f'必须是文件 {file}')
8
+
9
+
10
+ def checkPathOrNotExists(folder: Path):
11
+ btask.check(folder.is_dir() or not folder.exists(), f'必须是目录 {folder}')
@@ -0,0 +1,11 @@
1
+ {
2
+ "files.exclude": {
3
+ ".pytest_cache": true,
4
+ "**/__pycache__": true,
5
+ ".gitignore": true,
6
+ ".venv": true,
7
+ ".venv-lock": true,
8
+ "venv": true,
9
+ },
10
+ "python.defaultInterpreterPath": "${workspaceFolder}/venv/Scripts/python.exe",
11
+ }
@@ -7,7 +7,7 @@
7
7
  "command": "TortoiseGitProc.exe",
8
8
  "args": [
9
9
  "/command:commit",
10
- "/path:${workspaceFolder}/../",
10
+ "/path:${workspaceFolder}/",
11
11
  ],
12
12
  },
13
13
  {
@@ -25,7 +25,7 @@
25
25
  "command": "TortoiseGitProc.exe",
26
26
  "args": [
27
27
  "/command:revert",
28
- "/path:${workspaceFolder}/../",
28
+ "/path:${workspaceFolder}/",
29
29
  ],
30
30
  },
31
31
  {
@@ -43,7 +43,7 @@
43
43
  "command": "TortoiseGitProc.exe",
44
44
  "args": [
45
45
  "/command:sync",
46
- "/path:${workspaceFolder}/../",
46
+ "/path:${workspaceFolder}/",
47
47
  ],
48
48
  },
49
49
  {
@@ -52,7 +52,7 @@
52
52
  "command": "TortoiseGitProc.exe",
53
53
  "args": [
54
54
  "/command:log",
55
- "/path:${workspaceFolder}/../",
55
+ "/path:${workspaceFolder}/",
56
56
  ],
57
57
  },
58
58
  {
bcmd/tasks/lib.py CHANGED
@@ -7,7 +7,8 @@ import typer
7
7
  from beni import bcolor, bfile, bpath, btask
8
8
  from beni.bfunc import syncCall
9
9
 
10
- from bcmd.common import password
10
+ from ..common import password
11
+ from .venv import getPackageList
11
12
 
12
13
  app: Final = btask.newSubApp('lib 工具')
13
14
 
@@ -23,10 +24,10 @@ async def tidy_dependencies(
23
24
  workspace_path = Path.cwd()
24
25
  pyprojectTomlFile = workspace_path / 'pyproject.toml'
25
26
  btask.check(pyprojectTomlFile.is_file(), 'pyproject.toml 不存在', pyprojectTomlFile)
26
- targetVenvFileName = 'venv.lock' if with_version else 'venv.list'
27
- targetVenvFile = bpath.get(workspace_path, f'./../{targetVenvFileName}')
28
- btask.check(targetVenvFile.is_file(), '文件不存在', targetVenvFile)
29
- libAry = (await bfile.readText(targetVenvFile)).strip().replace('\r\n', '\n').split('\n')
27
+ venvFile = bpath.get(workspace_path, f'.venv')
28
+ btask.check(venvFile.is_file(), '.venv 不存在', venvFile)
29
+ basePackages, lockPackages = await getPackageList(venvFile)
30
+ libAry = lockPackages if with_version else basePackages
30
31
  oldContent = await bfile.readText(pyprojectTomlFile)
31
32
  ignoreLibAry = _getIgnoreLibAry(oldContent)
32
33
  ignoreLibAry = sorted(list(set(ignoreLibAry) & set(libAry)))
@@ -79,7 +80,7 @@ async def update_version(
79
80
  @app.command()
80
81
  @syncCall
81
82
  async def build(
82
- src_path: Path = typer.Argument(None, help='src 路径'),
83
+ workspace_path: Path = typer.Argument(None, help='workspace 路径'),
83
84
  keep_build_files: bool = typer.Option(False, '--keep-build-files', '-k', help='是否保留构建文件'),
84
85
  ):
85
86
  '发布项目'
@@ -87,22 +88,21 @@ async def build(
87
88
  # 获取用户名和密码
88
89
  u, p = await password.getPypi()
89
90
 
90
- if not src_path:
91
- src_path = Path.cwd()
92
- src_path = src_path.resolve()
91
+ if not workspace_path:
92
+ workspace_path = Path.cwd()
93
+ workspace_path = workspace_path.resolve()
93
94
 
94
95
  def removeUnusedPath():
95
- bpath.remove(src_path / 'dist')
96
- paths = bpath.listDir(src_path)
96
+ bpath.remove(workspace_path / 'dist')
97
+ paths = bpath.listDir(workspace_path)
97
98
  for x in paths:
98
99
  if x.name.endswith('.egg-info'):
99
100
  bpath.remove(x)
100
101
 
101
102
  try:
102
- with bpath.changePath(src_path):
103
+ with bpath.changePath(workspace_path):
103
104
  removeUnusedPath()
104
- scriptPath = (src_path / './../venv/Scripts').resolve()
105
- os.system(f'{scriptPath / "pip.exe"} install setuptools -U -i https://mirrors.aliyun.com/pypi/simple')
105
+ scriptPath = (workspace_path / './venv/Scripts').resolve()
106
106
  os.system(f'{scriptPath / "python.exe"} -m build')
107
107
  os.system(f'{scriptPath / "twine.exe"} upload dist/* -u {u} -p {p}')
108
108
  finally:
bcmd/tasks/proxy.py CHANGED
@@ -17,7 +17,7 @@ async def proxy(
17
17
  port: int = typer.Option(15236, help="代理服务器端口"),
18
18
  ):
19
19
  '生成终端设置代理服务器的命令'
20
- processNameAry = []
20
+ processNameAry:list[str] = []
21
21
  process = psutil.Process().parent()
22
22
  while process:
23
23
  processNameAry.append(process.name())
bcmd/tasks/venv.py CHANGED
@@ -1,15 +1,19 @@
1
1
  import importlib.resources
2
2
  import os
3
+ import platform
4
+ import re
3
5
  import sys
4
6
  from pathlib import Path
5
7
  from typing import Final
6
8
 
7
9
  import typer
8
- from beni import bcolor, bexecute, bfile, bhttp, binput, bpath, btask
10
+ from beni import bcolor, bexecute, bfile, bhttp, bpath, btask
9
11
  from beni.bfunc import syncCall
10
12
  from beni.btype import Null
13
+ from prettytable import PrettyTable
11
14
 
12
15
  from bcmd.common import password
16
+ from bcmd.common.func import checkFileOrNotExists, checkPathOrNotExists
13
17
 
14
18
  from . import bin
15
19
 
@@ -20,46 +24,52 @@ app: Final = btask.app
20
24
  @syncCall
21
25
  async def venv(
22
26
  packages: list[str] = typer.Argument(None),
23
- path: Path = typer.Option(None, '--path', '-p', help='指定路径,默认当前目录'),
24
- disabled_mirror: bool = typer.Option(False, '--disabled-mirror', '-d', help='是否禁用镜像'),
25
- new_project: bool = typer.Option(False, '--new-project', '-n', help='是否新建项目'),
26
- quiet: bool = typer.Option(False, '--quiet', '-q', help='是否安静模式'),
27
+ path: Path = typer.Option(None, '--path', help='指定路径,默认当前目录'),
28
+ isOfficial: bool = typer.Option(False, '--official', help='是否使用官方地址安装(https://pypi.org/simple)'),
29
+ isNewProject: bool = typer.Option(False, '--new-project', help='是否新建项目'),
30
+ isForceBase: bool = typer.Option(False, '--force-base', help='是否强制使用基础库去安装'),
31
+ isFullBase: bool = typer.Option(False, '--full-base', help='是否先清空venv目录再使用基础库去安装'),
27
32
  ):
28
33
  'python 虚拟环境配置'
34
+ btask.check(not (isForceBase == isFullBase == True), '不能同时使用 --force-base 和 --full-base')
29
35
  path = path or Path(os.getcwd())
30
36
  binPath = path / 'bin'
31
37
  binListFile = bpath.get(path, 'bin.list')
38
+ venvPath = bpath.get(path, 'venv')
39
+ checkPathOrNotExists(venvPath)
40
+ venvFile = bpath.get(path, '.venv')
41
+ checkFileOrNotExists(venvFile)
32
42
  await _inputQiniuPassword(binListFile, binPath)
43
+ if isFullBase:
44
+ bpath.remove(venvPath)
45
+ btask.check(not venvPath.exists(), f'无法删除 venv 目录 {venvPath}')
33
46
  packages = packages or []
34
47
  for i in range(len(packages)):
35
48
  package = packages[i]
36
49
  if package.endswith('==now'):
37
50
  ary = package.split('==')
38
51
  packages[i] = f'{ary[0]}=={await _getPackageLatestVersion(ary[0])}'
39
- venvPath = bpath.get(path, 'venv')
40
- assertPath(venvPath)
41
- if not venvPath.exists() and not quiet:
42
- await binput.confirm('指定目录为非venv目录,是否确认新创建?')
43
52
  if not venvPath.exists():
44
53
  await bexecute.run(f'python -m venv {venvPath}')
45
- venvLockFile = bpath.get(path, 'venv.lock')
46
- assertFile(venvLockFile)
47
- venvListFile = bpath.get(path, 'venv.list')
48
- assertFile(venvListFile)
49
- if not venvListFile.exists():
50
- await bfile.writeText(venvListFile, '')
51
- await tidyVenvFile(venvListFile, packages)
52
- if venvLockFile.exists():
53
- await tidyVenvFile(venvLockFile, packages)
54
- targetFile = venvLockFile
54
+ if not venvFile.exists():
55
+ await bfile.writeText(venvFile, '')
56
+ basePackages, lockPackages = await getPackageList(venvFile)
57
+ if isForceBase or isFullBase:
58
+ installPackages = _mergePackageList(basePackages, packages)
55
59
  else:
56
- targetFile = venvListFile
60
+ installPackages = _mergePackageList(lockPackages or basePackages, packages)
61
+ installPackages = sorted(list(set(installPackages)))
57
62
  if sys.platform.startswith('win'):
58
63
  pip = bpath.get(venvPath, 'Scripts/pip.exe')
59
64
  else:
60
65
  pip = bpath.get(venvPath, 'bin/pip')
61
- await pipInstall(pip, targetFile, disabled_mirror)
62
- await bexecute.run(f'{pip} freeze > {venvLockFile}')
66
+ await _pipInstall(pip, installPackages, isOfficial)
67
+ with bpath.useTempFile() as tempFile:
68
+ await bexecute.run(f'{pip} freeze > {tempFile}')
69
+ basePackages = _mergePackageList(basePackages, packages)
70
+ lockPackages = (await bfile.readText(tempFile)).strip().split('\n')
71
+ await updatePackageList(venvFile, basePackages, lockPackages)
72
+
63
73
  # 下载 bin 文件
64
74
  if binListFile.exists():
65
75
  bin.download(
@@ -68,47 +78,72 @@ async def venv(
68
78
  output=binPath,
69
79
  )
70
80
  # 新建项目
71
- if new_project:
72
- with bpath.changePath(path):
73
- await bexecute.run('beni venv --quiet')
81
+ if isNewProject:
74
82
  with importlib.resources.path('bcmd.resources', 'project') as sourceProjectPath:
75
- for p in bpath.listDir(sourceProjectPath):
83
+ for p in bpath.listPath(sourceProjectPath):
76
84
  bpath.copy(p, path / p.name)
77
85
  bcolor.printGreen('OK')
78
86
 
79
87
 
80
- async def pipInstall(pip: Path, file: Path, disabled_mirror: bool):
88
+ async def _pipInstall(pip: Path, installPackages: list[str], disabled_mirror: bool):
81
89
  python = pip.with_stem('python')
82
- btask.check(python.is_file(), '无法找到指定文件', python)
83
- btask.check(pip.is_file(), '无法找到指定文件', pip)
90
+ btask.check(python.is_file(), f'无法找到指定文件 {python}')
91
+ btask.check(pip.is_file(), f'无法找到指定文件 {pip}')
84
92
  indexUrl = '-i https://pypi.org/simple' if disabled_mirror else ''
85
- btask.check(not await bexecute.run(f'{python} -m pip install --upgrade pip {indexUrl}'), '更新 pip 失败')
86
- btask.check(not await bexecute.run(f'{pip} install -r {file} {indexUrl}'), '执行失败')
93
+ with bpath.useTempFile() as file:
94
+ await bfile.writeText(file, '\n'.join(installPackages))
95
+ table = PrettyTable()
96
+ table.add_column(
97
+ bcolor.yellow('#'),
98
+ [x + 1 for x in range(len(installPackages))],
99
+ )
100
+ table.add_column(
101
+ bcolor.yellow('安装库'),
102
+ [x for x in installPackages],
103
+ 'l',
104
+ )
105
+ print(table.get_string())
106
+
107
+ btask.check(
108
+ not await bexecute.run(f'{python} -m pip install --upgrade pip {indexUrl}'),
109
+ '更新 pip 失败',
110
+ )
111
+ btask.check(
112
+ not await bexecute.run(f'{pip} install -r {file} {indexUrl}'),
113
+ '执行失败',
114
+ )
115
+
87
116
 
117
+ async def _getPackageDict(venvFile: Path):
118
+ content = await bfile.readText(venvFile)
119
+ pattern = r'\[\[ (.*?) \]\]\n(.*?)(?=\n\[\[|\Z)'
120
+ matches: list[tuple[str, str]] = re.findall(pattern, content.strip(), re.DOTALL)
121
+ return {match[0]: [line.strip() for line in match[1].strip().split('\n') if line.strip()] for match in matches}
88
122
 
89
- async def tidyVenvFile(file: Path, packages: list[str]):
90
- packageNames = [getPackageName(x) for x in packages]
91
- ary = (await bfile.readText(file)).strip().replace('\r', '').split('\n')
92
- ary = list(filter(lambda x: getPackageName(x) not in packageNames, ary))
93
- ary.extend(packages)
94
- ary.sort()
95
- await bfile.writeText(file, '\n'.join(ary).strip())
96
123
 
124
+ _baseName: Final[str] = 'venv'
97
125
 
98
- def getPackageName(value: str):
99
- sep_ary = ['>', '<', '=']
100
- for sep in sep_ary:
101
- if sep in value:
102
- return value.split(sep)[0]
103
- return value
104
126
 
127
+ def _getLockName():
128
+ systemName = platform.system()
129
+ return f'{_baseName}-{systemName}'
105
130
 
106
- def assertFile(file: Path):
107
- btask.check(file.is_file() or not file.exists(), '必须是文件', file)
108
131
 
132
+ async def getPackageList(venvFile: Path):
133
+ result = await _getPackageDict(venvFile)
134
+ lockName = _getLockName()
135
+ return result.get(_baseName, []), result.get(lockName, [])
109
136
 
110
- def assertPath(folder: Path):
111
- btask.check(folder.is_dir() or not folder.exists(), '必须是目录', folder)
137
+
138
+ async def updatePackageList(venvFile: Path, packages: list[str], lockPackages: list[str]):
139
+ packageDict = await _getPackageDict(venvFile)
140
+ lockName = _getLockName()
141
+ packages.sort(key=lambda x: x.lower())
142
+ lockPackages.sort(key=lambda x: x.lower())
143
+ packageDict[_baseName] = packages
144
+ packageDict[lockName] = lockPackages
145
+ content = '\n'.join([f'\n[[ {key} ]]\n{'\n'.join(value)}' for key, value in packageDict.items()]).strip()
146
+ await bfile.writeText(venvFile, content)
112
147
 
113
148
 
114
149
  async def _getPackageLatestVersion(package: str):
@@ -119,6 +154,26 @@ async def _getPackageLatestVersion(package: str):
119
154
  return data['info']['version']
120
155
 
121
156
 
157
+ def _mergePackageList(basePackages: list[str], addPackages: list[str]):
158
+ basePackagesDict = {_getPackageName(x): x for x in basePackages}
159
+ addPackagesDict = {_getPackageName(x): x for x in addPackages}
160
+ packagesDict = basePackagesDict | addPackagesDict
161
+ return sorted([x for x in packagesDict.values()])
162
+
163
+
164
+ def _getPackageName(package: str):
165
+ if '==' in package:
166
+ package = package.split('==')[0]
167
+ elif '>' in package:
168
+ package = package.split('>')[0]
169
+ elif '<' in package:
170
+ package = package.split('<')[0]
171
+ package = package.strip()
172
+ if package.startswith('#'):
173
+ package = package.replace('#', '', 1).strip()
174
+ return package
175
+
176
+
122
177
  async def _inputQiniuPassword(binListFile: Path, binPath: Path) -> None:
123
178
  '根据需要输入七牛云密码'
124
179
  if binListFile.exists():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bcmd
3
- Version: 0.2.8
3
+ Version: 0.4.6
4
4
  Summary: Commands for Beni
5
5
  Author-email: Beni Mang <benimang@126.com>
6
6
  Maintainer-email: Beni Mang <benimang@126.com>
@@ -1,12 +1,13 @@
1
1
  bcmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  bcmd/main.py,sha256=1HRCHLt_jeF6ImgjG_MX9N2x9H1f6FyqTX7UADzedfA,131
3
3
  bcmd/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ bcmd/common/func.py,sha256=B5IFOcI0pfqKUNg91ry-vP-WZm9S22x7yzha1QMn2kM,296
4
5
  bcmd/common/password.py,sha256=25fA1h9ttZuUobnZ_nA0Ouhmk43etBfGeM40dgxJnFY,1347
5
6
  bcmd/resources/project/.gitignore,sha256=m8wh9WahP29_Ci866EEuj07Wfn0wnkomj7wldbxd29E,26
6
- bcmd/resources/project/src/main.py,sha256=xdskz_sf05fYA1SRMFCIxDjx8SnegxTbCmHpW86ItLs,11
7
- bcmd/resources/project/src/.vscode/launch.json,sha256=Wpghb9lW9Y1wtrjqlTbyjeejDuU8BQJmBjwsLyPRh1g,478
8
- bcmd/resources/project/src/.vscode/settings.json,sha256=roHbI_6eQNeaU2-LXZNbqwezf96p8_0dq_EgvA1wp7U,188
9
- bcmd/resources/project/src/.vscode/tasks.json,sha256=vajOT61PFvnrOHpfAy2yLjz0pN2ZWti0elR-OnbVCDw,1795
7
+ bcmd/resources/project/main.py,sha256=xdskz_sf05fYA1SRMFCIxDjx8SnegxTbCmHpW86ItLs,11
8
+ bcmd/resources/project/.vscode/launch.json,sha256=Wpghb9lW9Y1wtrjqlTbyjeejDuU8BQJmBjwsLyPRh1g,478
9
+ bcmd/resources/project/.vscode/settings.json,sha256=Ze0dt3KkKU1IiXMRiQfjbcKdSsS7XTD9PkaQn3wgEWs,290
10
+ bcmd/resources/project/.vscode/tasks.json,sha256=gouhpkrqiPz7v65Jw1Rz-BCYU3sSdmphzXIYCzVnoe0,1783
10
11
  bcmd/tasks/__init__.py,sha256=XDE4eW0mPkUCSK9tyg1DQRGLA7A9DuTmjq5MyUiPoXs,294
11
12
  bcmd/tasks/bin.py,sha256=rdag8IJv081CKflnJKo0IkVbi5wqBGowrl6gLMtP6Eg,3133
12
13
  bcmd/tasks/code.py,sha256=MEfzE879dplraLtZ59EZu94HrPkEohHCo7PNEoF_xmM,3089
@@ -15,15 +16,15 @@ bcmd/tasks/debian.py,sha256=B9aMIIct3vNqMJr5hTr1GegXVf20H49C27FMvRRGIzI,3004
15
16
  bcmd/tasks/download.py,sha256=0TYdoeEkXL--GTZ8ZSnSNzh8pC42kZhrTu6WVY5e7Fo,1824
16
17
  bcmd/tasks/image.py,sha256=OSqShLb_lwa77aQOnRNksXNemtuAnQDGg-VfiDy9fEM,2310
17
18
  bcmd/tasks/json.py,sha256=WWOyvcZPYaqQgp-Tkm-uIJschNMBKPKtZN3yXz_SC5s,635
18
- bcmd/tasks/lib.py,sha256=6J1amKBMSd9noRrsJ9vfbdgaRLeos8o7oNlqc5HOCU4,4689
19
+ bcmd/tasks/lib.py,sha256=6-1WGYUzBtr80K7zuQETLiQKpB9EfXvPxiL22a8u5v8,4583
19
20
  bcmd/tasks/math.py,sha256=M7-mmyQPx1UW7JiU1knY5Ty0hBw9zv9L4NNJf9eEjZ4,2857
20
21
  bcmd/tasks/mirror.py,sha256=-ztGkkxVk81npIo4cpmyLdHa1w4ZFdiJ3mv5WIBMI5Y,1556
21
22
  bcmd/tasks/project.py,sha256=ESWyRvRu4tesoYrlBtYMrQvQoxzMnFkI-jTN2hsYruI,939
22
- bcmd/tasks/proxy.py,sha256=6-qXy5_aFAJs8ikVsHTqC2R-QrMfjuJkyyVTxO7M0tk,1314
23
+ bcmd/tasks/proxy.py,sha256=mdiBR2vah5qKt9o7dXE7rg8Lz_A6GheVJDts0m1gmSs,1324
23
24
  bcmd/tasks/time.py,sha256=nSIVYov2LsGdxsZAtC91UKXcUtVAqR9o-JmzeuevFhA,2586
24
- bcmd/tasks/venv.py,sha256=u2Ogke5hU2eFb0YrFQ2JtxGiEcgfiHQj6lg0lqVUcF8,4602
25
- bcmd-0.2.8.dist-info/METADATA,sha256=UTakK1CwhfC4FBn-A53BI1lyaIBkqt742nWR2UMjX3M,486
26
- bcmd-0.2.8.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
27
- bcmd-0.2.8.dist-info/entry_points.txt,sha256=rHJrP6KEQpB-YaQqDFzEL2v88r03rxSfnzAayRvAqHU,39
28
- bcmd-0.2.8.dist-info/top_level.txt,sha256=-KrvhhtBcYsm4XhcjQvEcFbBB3VXeep7d3NIfDTrXKQ,5
29
- bcmd-0.2.8.dist-info/RECORD,,
25
+ bcmd/tasks/venv.py,sha256=U4Ac2B3jFFwGhzeuFdgNJ94WQ88dAJp71ffoCKbEsXU,6800
26
+ bcmd-0.4.6.dist-info/METADATA,sha256=PqZPpz2uBfhb7z-gf48uH_UZkY508_mGMsRpMfdvIOs,486
27
+ bcmd-0.4.6.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
28
+ bcmd-0.4.6.dist-info/entry_points.txt,sha256=rHJrP6KEQpB-YaQqDFzEL2v88r03rxSfnzAayRvAqHU,39
29
+ bcmd-0.4.6.dist-info/top_level.txt,sha256=-KrvhhtBcYsm4XhcjQvEcFbBB3VXeep7d3NIfDTrXKQ,5
30
+ bcmd-0.4.6.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- {
2
- "files.exclude": {
3
- ".pytest_cache": true,
4
- "**/__pycache__": true,
5
- },
6
- "python.defaultInterpreterPath": "${workspaceFolder}/../venv/Scripts/python.exe",
7
- }
File without changes
File without changes