Skip to content

Commit 88695ac

Browse files
authored
Add custom CLI for service startup (#697)
* Add custom CLI for service startup * Remove redundant scripts * Fix lint
1 parent 3b04329 commit 88695ac

File tree

10 files changed

+485
-39
lines changed

10 files changed

+485
-39
lines changed

backend/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
>
7373
> It is recommended to execute under the backend directory, and chmod authorization may be required
7474
75-
- `pre_start.sh`: Perform automatic database migration and create database tables
75+
- `pre_start.sh`: Perform automatic database migration
7676

7777
- `celery-start.sh`: For celery docker script, implementation is not recommended
7878

backend/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3+
4+
__version__ = '1.5.2'
5+
6+
from backend.utils.console import console
7+
8+
9+
def get_version() -> str | None:
10+
console.print(f'\n[cyan]{__version__}[/]')

backend/cli.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
from dataclasses import dataclass
4+
from typing import Annotated
5+
6+
import uvicorn
7+
8+
from cappa import Arg, Subcommands, invoke
9+
from rich.panel import Panel
10+
from rich.progress import (
11+
Progress,
12+
SpinnerColumn,
13+
TextColumn,
14+
TimeElapsedColumn,
15+
)
16+
from rich.text import Text
17+
18+
from backend import console, get_version
19+
from backend.core.conf import settings
20+
from backend.plugin.tools import get_plugins, install_requirements
21+
22+
23+
def run(host: str, port: int, reload: bool, workers: int | None) -> None:
24+
console.print(Text('检测插件依赖...', style='bold cyan'))
25+
26+
plugins = get_plugins()
27+
28+
with Progress(
29+
SpinnerColumn(finished_text='[bold green]插件依赖安装完成[/]'),
30+
TextColumn('[green]{task.completed}/{task.total}[/]'),
31+
TimeElapsedColumn(),
32+
console=console,
33+
) as progress:
34+
task = progress.add_task('安装插件依赖...', total=len(plugins))
35+
for i, plugin in enumerate(plugins):
36+
install_requirements(plugin)
37+
progress.advance(task)
38+
39+
url = f'http://{host}:{port}'
40+
docs_url = url + settings.FASTAPI_DOCS_URL
41+
redoc_url = url + settings.FASTAPI_REDOC_URL
42+
openapi_url = url + settings.FASTAPI_OPENAPI_URL
43+
44+
console.print(Text('启动 fba 服务...', style='bold magenta'))
45+
46+
panel_content = Text()
47+
panel_content.append(f'📝 Swagger 文档: {docs_url}\n', style='blue')
48+
panel_content.append(f'📚 Redoc 文档: {redoc_url}\n', style='yellow')
49+
panel_content.append(f'📡 OpenAPI JSON: {openapi_url}\n', style='green')
50+
panel_content.append(
51+
'🌍 fba 官方文档: https://fastapi-practices.github.io/fastapi_best_architecture_docs/',
52+
style='cyan',
53+
)
54+
55+
console.print(Panel(panel_content, title='fba 服务信息', border_style='purple', padding=(1, 2)))
56+
uvicorn.run(app='backend.main:app', host=host, port=port, reload=reload, workers=workers)
57+
58+
59+
@dataclass
60+
class Run:
61+
host: Annotated[
62+
str,
63+
Arg(
64+
long=True,
65+
default='127.0.0.1',
66+
help='提供服务的主机 IP 地址,对于本地开发,请使用 `127.0.0.1`。'
67+
'要启用公共访问,例如在局域网中,请使用 `0.0.0.0`',
68+
),
69+
]
70+
port: Annotated[
71+
int,
72+
Arg(long=True, default=8000, help='提供服务的主机端口号'),
73+
]
74+
reload: Annotated[
75+
bool,
76+
Arg(long=True, default=True, help='启用在(代码)文件更改时自动重新加载服务器'),
77+
]
78+
workers: Annotated[
79+
int | None,
80+
Arg(long=True, default=None, help='使用多个工作进程。与 `--reload` 标志互斥'),
81+
]
82+
83+
def __call__(self):
84+
run(host=self.host, port=self.port, reload=self.reload, workers=self.workers)
85+
86+
87+
@dataclass
88+
class FbaCli:
89+
version: Annotated[
90+
bool,
91+
Arg(short='-V', long=True, default=False, help='打印 fba 当前版本号'),
92+
]
93+
subcmd: Subcommands[Run | None] = None
94+
95+
def __call__(self):
96+
if self.version:
97+
get_version()
98+
99+
100+
def main() -> None:
101+
invoke(FbaCli)

backend/plugin/tools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def build_final_router() -> APIRouter:
251251
return main_router
252252

253253

254-
def install_requirements(plugin: str) -> None:
254+
def install_requirements(plugin: str | None) -> None:
255255
"""
256256
安装插件依赖
257257
@@ -268,8 +268,8 @@ def install_requirements(plugin: str) -> None:
268268
pip_install = [sys.executable, '-m', 'pip', 'install', '-r', requirements_file]
269269
if settings.PLUGIN_PIP_CHINA:
270270
pip_install.extend(['-i', settings.PLUGIN_PIP_INDEX_URL])
271-
subprocess.check_call(ensurepip_install)
272-
subprocess.check_call(pip_install)
271+
subprocess.check_call(ensurepip_install, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
272+
subprocess.check_call(pip_install, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
273273
except subprocess.CalledProcessError as e:
274274
raise PluginInjectError(f'插件 {plugin} 依赖安装失败:{e.stderr}') from e
275275

backend/pre_start.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,3 @@
33
alembic revision --autogenerate
44

55
alembic upgrade head
6-
7-
python3 ./scripts/init_data.py

backend/scripts/init_data.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

backend/utils/console.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
from rich import get_console
4+
5+
console = get_console()

pyproject.toml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[project]
22
name = "fastapi_best_architecture"
3-
version = "0.0.1"
43
description = """
54
A RBAC (Role-Based Access Control) permission control system built on FastAPI, featuring a unique pseudo-three-tier
65
architecture design, with built-in basic implementation of fastapi admin as a template library, free and open-source.
@@ -10,7 +9,8 @@ authors = [
109
]
1110
readme = "README.md"
1211
license = { text = "MIT" }
13-
requires-python = ">=3.10,<3.13"
12+
requires-python = ">=3.10"
13+
dynamic = ['version']
1414
dependencies = [
1515
"aiofiles>=24.1.0",
1616
"alembic>=1.14.1",
@@ -19,14 +19,14 @@ dependencies = [
1919
"asyncmy>=0.2.10",
2020
"asyncpg>=0.30.0",
2121
"bcrypt>=4.2.1",
22+
"cappa>=0.28.0",
2223
"celery==5.3.6",
2324
# When celery version < 6.0.0
2425
# https://github.com/celery/celery/issues/7874
2526
"celery-aio-pool==0.1.0rc8",
2627
"cryptography>=44.0.0",
2728
"dulwich>=0.22.8",
2829
"fast-captcha>=0.3.2",
29-
"fastapi-cli==0.0.5",
3030
"fastapi-limiter>=0.1.6",
3131
"fastapi-pagination>=0.13.0",
3232
"fastapi[standard]==0.115.11",
@@ -66,10 +66,22 @@ server = [
6666
]
6767

6868
[tool.uv]
69-
package = false
7069
python-downloads = "manual"
7170
default-groups = ["dev", "lint"]
7271

7372
[[tool.uv.index]]
7473
name = "aliyun"
7574
url = "https://mirrors.aliyun.com/pypi/simple"
75+
76+
[tool.hatch.build.targets.wheel]
77+
packages = ["backend"]
78+
79+
[tool.hatch.version]
80+
path = "backend/__init__.py"
81+
82+
[project.scripts]
83+
fba = "backend.cli:main"
84+
85+
[build-system]
86+
requires = ["hatchling"]
87+
build-backend = "hatchling.build"

requirements.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# This file was autogenerated by uv via the following command:
22
# uv export -o requirements.txt --no-hashes
3+
-e .
34
aiofiles==24.1.0
45
# via fastapi-best-architecture
56
alembic==1.15.1
@@ -31,6 +32,8 @@ bidict==0.23.1
3132
# via python-socketio
3233
billiard==4.2.1
3334
# via celery
35+
cappa==0.28.0
36+
# via fastapi-best-architecture
3437
celery==5.3.6
3538
# via
3639
# celery-aio-pool
@@ -92,9 +95,7 @@ fastapi==0.115.11
9295
# fastapi-limiter
9396
# fastapi-pagination
9497
fastapi-cli==0.0.5
95-
# via
96-
# fastapi
97-
# fastapi-best-architecture
98+
# via fastapi
9899
fastapi-limiter==0.1.6
99100
# via fastapi-best-architecture
100101
fastapi-pagination==0.13.0
@@ -228,7 +229,9 @@ redis==5.2.1
228229
# fastapi-best-architecture
229230
# fastapi-limiter
230231
rich==13.9.4
231-
# via typer
232+
# via
233+
# cappa
234+
# typer
232235
rsa==4.9
233236
# via python-jose
234237
rtoml==0.12.0
@@ -264,19 +267,23 @@ tomli==2.2.1 ; python_full_version < '3.11'
264267
# via pytest
265268
tornado==6.4.2
266269
# via flower
270+
type-lens==0.2.3
271+
# via cappa
267272
typer==0.15.2
268273
# via fastapi-cli
269274
typing-extensions==4.13.0
270275
# via
271276
# alembic
272277
# anyio
273278
# asgiref
279+
# cappa
274280
# fastapi
275281
# fastapi-pagination
276282
# pydantic
277283
# pydantic-core
278284
# rich
279285
# sqlalchemy
286+
# type-lens
280287
# typer
281288
# typing-inspection
282289
# uvicorn

0 commit comments

Comments
 (0)