bcmd 0.5.3__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.3.dist-info → bcmd-0.5.4.dist-info}/METADATA +1 -1
- bcmd-0.5.4.dist-info/RECORD +30 -0
- bcmd-0.5.3.dist-info/RECORD +0 -30
- {bcmd-0.5.3.dist-info → bcmd-0.5.4.dist-info}/WHEEL +0 -0
- {bcmd-0.5.3.dist-info → bcmd-0.5.4.dist-info}/entry_points.txt +0 -0
- {bcmd-0.5.3.dist-info → bcmd-0.5.4.dist-info}/top_level.txt +0 -0
bcmd/common/func.py
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import importlib.resources
|
|
2
|
-
from contextlib import contextmanager
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
from beni import btask
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def checkFileOrNotExists(file: Path):
|
|
9
|
-
btask.assertTrue(file.is_file() or not file.exists(), f'必须是文件 {file}')
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def checkPathOrNotExists(folder: Path):
|
|
13
|
-
btask.assertTrue(folder.is_dir() or not folder.exists(), f'必须是目录 {folder}')
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@contextmanager
|
|
17
|
-
def useResources(name: str):
|
|
18
|
-
with importlib.resources.path('bcmd.resources', name) as target:
|
|
19
|
-
yield target
|
|
1
|
+
import importlib.resources
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from beni import btask
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def checkFileOrNotExists(file: Path):
|
|
9
|
+
btask.assertTrue(file.is_file() or not file.exists(), f'必须是文件 {file}')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def checkPathOrNotExists(folder: Path):
|
|
13
|
+
btask.assertTrue(folder.is_dir() or not folder.exists(), f'必须是目录 {folder}')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@contextmanager
|
|
17
|
+
def useResources(name: str):
|
|
18
|
+
with importlib.resources.path('bcmd.resources', name) as target:
|
|
19
|
+
yield target
|
bcmd/common/password.py
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import getpass
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
from beni import bcache, bcrypto
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@bcache.cache
|
|
8
|
-
async def getPypi() -> tuple[str, str]:
|
|
9
|
-
content = 'QbuF2mV/lqovtF5dskZGD7qHknYbNuF2QseWRtWxLZTPrC/jL1tcxV8JEKaRjLsu46PxJZ7zepJwggnUTIWnEAoV5VtgP2/hbuzxxHha8817kR5c65H9fXm8eOal7DYXsUoGPQMnm59UWNXUKjmIaP4sn9nySFlRYqa8sEZSbYQ4N0NL35Dpj1e3wyQxJ+7h2jwKAz50Hh8G4yAM3/js9+NUe4ymts+UXcwsP3ADIBMkzjnFc0lEYg2d+fw0A74XWCvoZPoGqHZR/THUOVNAYxoGgDzP4SPIk1XsmtpxvfO/DpJd/Cg/0fB3MYagGKI1+m6Bxqhvd1I/lf0YbM5y4E4='
|
|
10
|
-
data = _getData(content)
|
|
11
|
-
return data['username'], data['password']
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@bcache.cache
|
|
15
|
-
async def getQiniu() -> tuple[str, str]:
|
|
16
|
-
content = '7xOuA0FPCndTWcWmWLbqklQTqLTAhuEw9CarRTBYhWQ/g8wPxktw6VAiu50TLv49D1L8oCVfGafsowYDZw/prF6NQwCluPcCMy5JfdC9sKauvuZa51Nsf6PTR1UIyU8ZLUSzH+Ec2Ufcz/yAZCrcAtn63zMHNu3tTAVcZNPL597lSHdSRkpmDR8CaoUh/raH/Q=='
|
|
17
|
-
data = _getData(content)
|
|
18
|
-
return data['ak'], data['sk']
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _getData(content: str) -> dict[str, Any]:
|
|
22
|
-
index = content.find(' ')
|
|
23
|
-
if index > -1:
|
|
24
|
-
tips = f'请输入密码({content[:index]}):'
|
|
25
|
-
else:
|
|
26
|
-
tips = '请输入密码:'
|
|
27
|
-
while True:
|
|
28
|
-
try:
|
|
29
|
-
pwd = getpass.getpass(tips)
|
|
30
|
-
return bcrypto.decryptJson(content, pwd)
|
|
31
|
-
except KeyboardInterrupt:
|
|
32
|
-
raise Exception('操作取消')
|
|
33
|
-
except BaseException:
|
|
34
|
-
pass
|
|
1
|
+
import getpass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from beni import bcache, bcrypto
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@bcache.cache
|
|
8
|
+
async def getPypi() -> tuple[str, str]:
|
|
9
|
+
content = 'QbuF2mV/lqovtF5dskZGD7qHknYbNuF2QseWRtWxLZTPrC/jL1tcxV8JEKaRjLsu46PxJZ7zepJwggnUTIWnEAoV5VtgP2/hbuzxxHha8817kR5c65H9fXm8eOal7DYXsUoGPQMnm59UWNXUKjmIaP4sn9nySFlRYqa8sEZSbYQ4N0NL35Dpj1e3wyQxJ+7h2jwKAz50Hh8G4yAM3/js9+NUe4ymts+UXcwsP3ADIBMkzjnFc0lEYg2d+fw0A74XWCvoZPoGqHZR/THUOVNAYxoGgDzP4SPIk1XsmtpxvfO/DpJd/Cg/0fB3MYagGKI1+m6Bxqhvd1I/lf0YbM5y4E4='
|
|
10
|
+
data = _getData(content)
|
|
11
|
+
return data['username'], data['password']
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@bcache.cache
|
|
15
|
+
async def getQiniu() -> tuple[str, str]:
|
|
16
|
+
content = '7xOuA0FPCndTWcWmWLbqklQTqLTAhuEw9CarRTBYhWQ/g8wPxktw6VAiu50TLv49D1L8oCVfGafsowYDZw/prF6NQwCluPcCMy5JfdC9sKauvuZa51Nsf6PTR1UIyU8ZLUSzH+Ec2Ufcz/yAZCrcAtn63zMHNu3tTAVcZNPL597lSHdSRkpmDR8CaoUh/raH/Q=='
|
|
17
|
+
data = _getData(content)
|
|
18
|
+
return data['ak'], data['sk']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _getData(content: str) -> dict[str, Any]:
|
|
22
|
+
index = content.find(' ')
|
|
23
|
+
if index > -1:
|
|
24
|
+
tips = f'请输入密码({content[:index]}):'
|
|
25
|
+
else:
|
|
26
|
+
tips = '请输入密码:'
|
|
27
|
+
while True:
|
|
28
|
+
try:
|
|
29
|
+
pwd = getpass.getpass(tips)
|
|
30
|
+
return bcrypto.decryptJson(content, pwd)
|
|
31
|
+
except KeyboardInterrupt:
|
|
32
|
+
raise Exception('操作取消')
|
|
33
|
+
except BaseException:
|
|
34
|
+
pass
|
bcmd/main.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from beni import btask
|
|
4
|
-
|
|
5
|
-
from .tasks import *
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def run():
|
|
9
|
-
btask.options.lock = 0
|
|
10
|
-
asyncio.run(btask.main())
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from beni import btask
|
|
4
|
+
|
|
5
|
+
from .tasks import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def run():
|
|
9
|
+
btask.options.lock = 0
|
|
10
|
+
asyncio.run(btask.main())
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Use IntelliSense to learn about possible attributes.
|
|
3
|
-
// Hover to view descriptions of existing attributes.
|
|
4
|
-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
-
"version": "0.2.0",
|
|
6
|
-
"configurations": [
|
|
7
|
-
{
|
|
8
|
-
"name": "Python: main.py",
|
|
9
|
-
"type": "debugpy",
|
|
10
|
-
"request": "launch",
|
|
11
|
-
// "console": "internalConsole",
|
|
12
|
-
"program": "${workspaceFolder}/main.py"
|
|
13
|
-
}
|
|
14
|
-
]
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Python: main.py",
|
|
9
|
+
"type": "debugpy",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
// "console": "internalConsole",
|
|
12
|
+
"program": "${workspaceFolder}/main.py"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
15
|
}
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "2.0.0",
|
|
3
|
-
"tasks": [
|
|
4
|
-
{
|
|
5
|
-
"label": "git commit",
|
|
6
|
-
"problemMatcher": [],
|
|
7
|
-
"command": "TortoiseGitProc.exe",
|
|
8
|
-
"args": [
|
|
9
|
-
"/command:commit",
|
|
10
|
-
"/path:${workspaceFolder}/",
|
|
11
|
-
],
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"label": "git commit file",
|
|
15
|
-
"problemMatcher": [],
|
|
16
|
-
"command": "TortoiseGitProc.exe",
|
|
17
|
-
"args": [
|
|
18
|
-
"/command:commit",
|
|
19
|
-
"/path:${file}",
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"label": "git revert",
|
|
24
|
-
"problemMatcher": [],
|
|
25
|
-
"command": "TortoiseGitProc.exe",
|
|
26
|
-
"args": [
|
|
27
|
-
"/command:revert",
|
|
28
|
-
"/path:${workspaceFolder}/",
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"label": "git revert file",
|
|
33
|
-
"problemMatcher": [],
|
|
34
|
-
"command": "TortoiseGitProc.exe",
|
|
35
|
-
"args": [
|
|
36
|
-
"/command:revert",
|
|
37
|
-
"/path:${file}",
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"label": "git sync",
|
|
42
|
-
"problemMatcher": [],
|
|
43
|
-
"command": "TortoiseGitProc.exe",
|
|
44
|
-
"args": [
|
|
45
|
-
"/command:sync",
|
|
46
|
-
"/path:${workspaceFolder}/",
|
|
47
|
-
],
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"label": "git log",
|
|
51
|
-
"problemMatcher": [],
|
|
52
|
-
"command": "TortoiseGitProc.exe",
|
|
53
|
-
"args": [
|
|
54
|
-
"/command:log",
|
|
55
|
-
"/path:${workspaceFolder}/",
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"label": "git log file",
|
|
60
|
-
"problemMatcher": [],
|
|
61
|
-
"command": "TortoiseGitProc.exe",
|
|
62
|
-
"args": [
|
|
63
|
-
"/command:log",
|
|
64
|
-
"/path:${file}",
|
|
65
|
-
],
|
|
66
|
-
},
|
|
67
|
-
],
|
|
1
|
+
{
|
|
2
|
+
"version": "2.0.0",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"label": "git commit",
|
|
6
|
+
"problemMatcher": [],
|
|
7
|
+
"command": "TortoiseGitProc.exe",
|
|
8
|
+
"args": [
|
|
9
|
+
"/command:commit",
|
|
10
|
+
"/path:${workspaceFolder}/",
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"label": "git commit file",
|
|
15
|
+
"problemMatcher": [],
|
|
16
|
+
"command": "TortoiseGitProc.exe",
|
|
17
|
+
"args": [
|
|
18
|
+
"/command:commit",
|
|
19
|
+
"/path:${file}",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"label": "git revert",
|
|
24
|
+
"problemMatcher": [],
|
|
25
|
+
"command": "TortoiseGitProc.exe",
|
|
26
|
+
"args": [
|
|
27
|
+
"/command:revert",
|
|
28
|
+
"/path:${workspaceFolder}/",
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"label": "git revert file",
|
|
33
|
+
"problemMatcher": [],
|
|
34
|
+
"command": "TortoiseGitProc.exe",
|
|
35
|
+
"args": [
|
|
36
|
+
"/command:revert",
|
|
37
|
+
"/path:${file}",
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"label": "git sync",
|
|
42
|
+
"problemMatcher": [],
|
|
43
|
+
"command": "TortoiseGitProc.exe",
|
|
44
|
+
"args": [
|
|
45
|
+
"/command:sync",
|
|
46
|
+
"/path:${workspaceFolder}/",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"label": "git log",
|
|
51
|
+
"problemMatcher": [],
|
|
52
|
+
"command": "TortoiseGitProc.exe",
|
|
53
|
+
"args": [
|
|
54
|
+
"/command:log",
|
|
55
|
+
"/path:${workspaceFolder}/",
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"label": "git log file",
|
|
60
|
+
"problemMatcher": [],
|
|
61
|
+
"command": "TortoiseGitProc.exe",
|
|
62
|
+
"args": [
|
|
63
|
+
"/command:log",
|
|
64
|
+
"/path:${file}",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
68
|
}
|
bcmd/tasks/__init__.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# type: ignore
|
|
2
|
-
from . import bin
|
|
3
|
-
from . import code
|
|
4
|
-
from . import crypto
|
|
5
|
-
from . import debian
|
|
6
|
-
from . import download
|
|
7
|
-
from . import image
|
|
8
|
-
from . import json
|
|
9
|
-
from . import lib
|
|
10
|
-
from . import math
|
|
11
|
-
from . import mirror
|
|
12
|
-
from . import project
|
|
13
|
-
from . import proxy
|
|
14
|
-
from . import time
|
|
15
|
-
from . import venv
|
|
1
|
+
# type: ignore
|
|
2
|
+
from . import bin
|
|
3
|
+
from . import code
|
|
4
|
+
from . import crypto
|
|
5
|
+
from . import debian
|
|
6
|
+
from . import download
|
|
7
|
+
from . import image
|
|
8
|
+
from . import json
|
|
9
|
+
from . import lib
|
|
10
|
+
from . import math
|
|
11
|
+
from . import mirror
|
|
12
|
+
from . import project
|
|
13
|
+
from . import proxy
|
|
14
|
+
from . import time
|
|
15
|
+
from . import venv
|
bcmd/tasks/bin.py
CHANGED
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Final
|
|
4
|
-
|
|
5
|
-
import typer
|
|
6
|
-
from beni import bcolor, bfile, bpath, btask, bzip
|
|
7
|
-
from beni.bfunc import syncCall, textToAry
|
|
8
|
-
from beni.bqiniu import QiniuBucket
|
|
9
|
-
from beni.btype import Null
|
|
10
|
-
from prettytable import PrettyTable
|
|
11
|
-
|
|
12
|
-
from ..common import password
|
|
13
|
-
|
|
14
|
-
app: Final = btask.newSubApp('bin 工具')
|
|
15
|
-
|
|
16
|
-
_PREFIX = 'bin/'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@app.command()
|
|
20
|
-
@syncCall
|
|
21
|
-
async def download(
|
|
22
|
-
names: list[str] = typer.Argument(None, help="支持多个"),
|
|
23
|
-
file: Path = typer.Option(None, '--file', '-f', help="文件形式指定参数,行为单位"),
|
|
24
|
-
output: Path = typer.Option(Path.cwd(), '--output', '-o', help="本地保存路径"),
|
|
25
|
-
):
|
|
26
|
-
'从七牛云下载执行文件'
|
|
27
|
-
bucket: QiniuBucket = Null
|
|
28
|
-
if file:
|
|
29
|
-
content = await bfile.readText(Path(file))
|
|
30
|
-
names.extend(
|
|
31
|
-
textToAry(content)
|
|
32
|
-
)
|
|
33
|
-
for target in names:
|
|
34
|
-
binFile = output / target
|
|
35
|
-
if binFile.exists():
|
|
36
|
-
bcolor.printYellow(f'已存在 {binFile}')
|
|
37
|
-
else:
|
|
38
|
-
key = f'bin/{target}.zip'
|
|
39
|
-
bucket = bucket or await _getBucket()
|
|
40
|
-
await bucket.downloadPrivateFileUnzip(key, output)
|
|
41
|
-
bcolor.printGreen(f'added {binFile}')
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@app.command('list')
|
|
45
|
-
@syncCall
|
|
46
|
-
async def getList():
|
|
47
|
-
'列出可下载的文件'
|
|
48
|
-
bucket = await _getBucket()
|
|
49
|
-
datas = (await bucket.getFileList(_PREFIX, limit=1000))[0]
|
|
50
|
-
datas = [x for x in datas if x.key != _PREFIX and x.key.endswith('.zip')]
|
|
51
|
-
datas.sort(key=lambda x: x.time, reverse=True)
|
|
52
|
-
table = PrettyTable()
|
|
53
|
-
table.add_column(
|
|
54
|
-
bcolor.yellow('文件名称'),
|
|
55
|
-
[x.key[len(_PREFIX):-len('.zip')] for x in datas],
|
|
56
|
-
'l',
|
|
57
|
-
)
|
|
58
|
-
table.add_column(
|
|
59
|
-
bcolor.yellow('上传时间'),
|
|
60
|
-
[datetime.fromtimestamp(x.time / 10000000).strftime('%Y-%m-%d %H:%M:%S') for x in datas],
|
|
61
|
-
)
|
|
62
|
-
print()
|
|
63
|
-
print(table.get_string())
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@app.command()
|
|
67
|
-
@syncCall
|
|
68
|
-
async def upload(
|
|
69
|
-
file: Path = typer.Argument(..., help="本地文件路径"),
|
|
70
|
-
force: bool = typer.Option(False, '--force', '-f', help="强制覆盖"),
|
|
71
|
-
):
|
|
72
|
-
'上传'
|
|
73
|
-
bucket = await _getBucket()
|
|
74
|
-
key = f'{_PREFIX}{file.name}.zip'
|
|
75
|
-
if not force:
|
|
76
|
-
if await bucket.getFileStatus(key):
|
|
77
|
-
btask.abort('云端文件已存在,可以使用 --force 强制覆盖')
|
|
78
|
-
with bpath.useTempFile() as f:
|
|
79
|
-
bzip.zipFile(f, file)
|
|
80
|
-
await bucket.uploadFile(key, f)
|
|
81
|
-
bcolor.printGreen('OK')
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@app.command()
|
|
85
|
-
@syncCall
|
|
86
|
-
async def remove(
|
|
87
|
-
key: str = typer.Argument(..., help="云端文件key"),
|
|
88
|
-
):
|
|
89
|
-
bucket = await _getBucket()
|
|
90
|
-
await bucket.deleteFiles(f'{_PREFIX}{key}.zip')
|
|
91
|
-
bcolor.printGreen('OK')
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# ------------------------------------------------------------------------------------
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
async def _getBucket():
|
|
98
|
-
ak, sk = await password.getQiniu()
|
|
99
|
-
return QiniuBucket(
|
|
100
|
-
'pytask',
|
|
101
|
-
'http://qiniu-cdn.pytask.com',
|
|
102
|
-
ak,
|
|
103
|
-
sk,
|
|
104
|
-
)
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from beni import bcolor, bfile, bpath, btask, bzip
|
|
7
|
+
from beni.bfunc import syncCall, textToAry
|
|
8
|
+
from beni.bqiniu import QiniuBucket
|
|
9
|
+
from beni.btype import Null
|
|
10
|
+
from prettytable import PrettyTable
|
|
11
|
+
|
|
12
|
+
from ..common import password
|
|
13
|
+
|
|
14
|
+
app: Final = btask.newSubApp('bin 工具')
|
|
15
|
+
|
|
16
|
+
_PREFIX = 'bin/'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command()
|
|
20
|
+
@syncCall
|
|
21
|
+
async def download(
|
|
22
|
+
names: list[str] = typer.Argument(None, help="支持多个"),
|
|
23
|
+
file: Path = typer.Option(None, '--file', '-f', help="文件形式指定参数,行为单位"),
|
|
24
|
+
output: Path = typer.Option(Path.cwd(), '--output', '-o', help="本地保存路径"),
|
|
25
|
+
):
|
|
26
|
+
'从七牛云下载执行文件'
|
|
27
|
+
bucket: QiniuBucket = Null
|
|
28
|
+
if file:
|
|
29
|
+
content = await bfile.readText(Path(file))
|
|
30
|
+
names.extend(
|
|
31
|
+
textToAry(content)
|
|
32
|
+
)
|
|
33
|
+
for target in names:
|
|
34
|
+
binFile = output / target
|
|
35
|
+
if binFile.exists():
|
|
36
|
+
bcolor.printYellow(f'已存在 {binFile}')
|
|
37
|
+
else:
|
|
38
|
+
key = f'bin/{target}.zip'
|
|
39
|
+
bucket = bucket or await _getBucket()
|
|
40
|
+
await bucket.downloadPrivateFileUnzip(key, output)
|
|
41
|
+
bcolor.printGreen(f'added {binFile}')
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.command('list')
|
|
45
|
+
@syncCall
|
|
46
|
+
async def getList():
|
|
47
|
+
'列出可下载的文件'
|
|
48
|
+
bucket = await _getBucket()
|
|
49
|
+
datas = (await bucket.getFileList(_PREFIX, limit=1000))[0]
|
|
50
|
+
datas = [x for x in datas if x.key != _PREFIX and x.key.endswith('.zip')]
|
|
51
|
+
datas.sort(key=lambda x: x.time, reverse=True)
|
|
52
|
+
table = PrettyTable()
|
|
53
|
+
table.add_column(
|
|
54
|
+
bcolor.yellow('文件名称'),
|
|
55
|
+
[x.key[len(_PREFIX):-len('.zip')] for x in datas],
|
|
56
|
+
'l',
|
|
57
|
+
)
|
|
58
|
+
table.add_column(
|
|
59
|
+
bcolor.yellow('上传时间'),
|
|
60
|
+
[datetime.fromtimestamp(x.time / 10000000).strftime('%Y-%m-%d %H:%M:%S') for x in datas],
|
|
61
|
+
)
|
|
62
|
+
print()
|
|
63
|
+
print(table.get_string())
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.command()
|
|
67
|
+
@syncCall
|
|
68
|
+
async def upload(
|
|
69
|
+
file: Path = typer.Argument(..., help="本地文件路径"),
|
|
70
|
+
force: bool = typer.Option(False, '--force', '-f', help="强制覆盖"),
|
|
71
|
+
):
|
|
72
|
+
'上传'
|
|
73
|
+
bucket = await _getBucket()
|
|
74
|
+
key = f'{_PREFIX}{file.name}.zip'
|
|
75
|
+
if not force:
|
|
76
|
+
if await bucket.getFileStatus(key):
|
|
77
|
+
btask.abort('云端文件已存在,可以使用 --force 强制覆盖')
|
|
78
|
+
with bpath.useTempFile() as f:
|
|
79
|
+
bzip.zipFile(f, file)
|
|
80
|
+
await bucket.uploadFile(key, f)
|
|
81
|
+
bcolor.printGreen('OK')
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@app.command()
|
|
85
|
+
@syncCall
|
|
86
|
+
async def remove(
|
|
87
|
+
key: str = typer.Argument(..., help="云端文件key"),
|
|
88
|
+
):
|
|
89
|
+
bucket = await _getBucket()
|
|
90
|
+
await bucket.deleteFiles(f'{_PREFIX}{key}.zip')
|
|
91
|
+
bcolor.printGreen('OK')
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ------------------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def _getBucket():
|
|
98
|
+
ak, sk = await password.getQiniu()
|
|
99
|
+
return QiniuBucket(
|
|
100
|
+
'pytask',
|
|
101
|
+
'http://qiniu-cdn.pytask.com',
|
|
102
|
+
ak,
|
|
103
|
+
sk,
|
|
104
|
+
)
|