servly 0.1.0__tar.gz → 0.2.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.
- servly-0.2.0/PKG-INFO +133 -0
- servly-0.2.0/README.md +119 -0
- {servly-0.1.0 → servly-0.2.0}/pyproject.toml +11 -3
- servly-0.2.0/servly/__init__.py +5 -0
- servly-0.2.0/servly/cli.py +295 -0
- servly-0.2.0/servly/logs.py +266 -0
- servly-0.2.0/servly/service.py +213 -0
- servly-0.2.0/servly.egg-info/PKG-INFO +133 -0
- servly-0.2.0/servly.egg-info/SOURCES.txt +17 -0
- servly-0.2.0/servly.egg-info/entry_points.txt +2 -0
- servly-0.2.0/servly.egg-info/requires.txt +1 -0
- servly-0.2.0/servly.egg-info/top_level.txt +1 -0
- servly-0.2.0/tests/test_advanced.py +228 -0
- servly-0.2.0/tests/test_config.py +51 -0
- servly-0.2.0/tests/test_integration.py +275 -0
- servly-0.2.0/tests/test_logs.py +110 -0
- servly-0.2.0/tests/test_service_management.py +121 -0
- servly-0.1.0/PKG-INFO +0 -14
- servly-0.1.0/README.md +0 -1
- servly-0.1.0/servly.egg-info/PKG-INFO +0 -14
- servly-0.1.0/servly.egg-info/SOURCES.txt +0 -9
- servly-0.1.0/servly.egg-info/entry_points.txt +0 -2
- servly-0.1.0/servly.egg-info/top_level.txt +0 -1
- servly-0.1.0/xm/__init__.py +0 -1
- servly-0.1.0/xm/cli.py +0 -7
- {servly-0.1.0 → servly-0.2.0}/servly.egg-info/dependency_links.txt +0 -0
- {servly-0.1.0 → servly-0.2.0}/setup.cfg +0 -0
servly-0.2.0/PKG-INFO
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: servly
|
3
|
+
Version: 0.2.0
|
4
|
+
Summary: simple process manager
|
5
|
+
Author-email: simpxx <simpxx@gmail.com>
|
6
|
+
License: MIT
|
7
|
+
Keywords: command-line,tool
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.12
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: pyyaml>=6.0.2
|
14
|
+
|
15
|
+
# SERVLY
|
16
|
+
|
17
|
+
A simple process management tool for Linux, similar to PM2, designed to simplify application deployment and management.
|
18
|
+
|
19
|
+
## Features
|
20
|
+
|
21
|
+
- Start, stop, and restart services defined in a `servly.yml` configuration file
|
22
|
+
- View real-time logs with service name highlighting
|
23
|
+
- Automatic process supervision and PID management
|
24
|
+
- Environment variable support
|
25
|
+
- Simple YAML configuration
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
```bash
|
30
|
+
# Using pip
|
31
|
+
pip install servly
|
32
|
+
|
33
|
+
# From source
|
34
|
+
git clone https://github.com/yourusername/servly.git
|
35
|
+
cd servly
|
36
|
+
pip install -e .
|
37
|
+
```
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
### Quick Start
|
42
|
+
|
43
|
+
1. Create a `servly.yml` file in your project:
|
44
|
+
|
45
|
+
```yaml
|
46
|
+
# Basic format: service-name: command
|
47
|
+
web-server: node server.js
|
48
|
+
|
49
|
+
# Detailed format
|
50
|
+
api:
|
51
|
+
cmd: python api.py
|
52
|
+
cwd: ./api
|
53
|
+
env:
|
54
|
+
NODE_ENV: production
|
55
|
+
```
|
56
|
+
|
57
|
+
2. Start your services:
|
58
|
+
|
59
|
+
```bash
|
60
|
+
servly start
|
61
|
+
```
|
62
|
+
|
63
|
+
### Core Commands
|
64
|
+
|
65
|
+
- **Start Services**:
|
66
|
+
```bash
|
67
|
+
servly start [all | service-name]
|
68
|
+
```
|
69
|
+
Starts all services or a specific service by name.
|
70
|
+
|
71
|
+
- **Stop Services**:
|
72
|
+
```bash
|
73
|
+
servly stop [all | service-name]
|
74
|
+
```
|
75
|
+
Stops all running services or a specific service by name.
|
76
|
+
|
77
|
+
- **Restart Services**:
|
78
|
+
```bash
|
79
|
+
servly restart [all | service-name]
|
80
|
+
```
|
81
|
+
Restarts all services or a specific service by name.
|
82
|
+
|
83
|
+
- **View Service Logs**:
|
84
|
+
```bash
|
85
|
+
servly log [all | service-name]
|
86
|
+
```
|
87
|
+
Shows logs in real-time (similar to `tail -f`).
|
88
|
+
|
89
|
+
- **List Services**:
|
90
|
+
```bash
|
91
|
+
servly list
|
92
|
+
```
|
93
|
+
Shows status of all configured services.
|
94
|
+
|
95
|
+
## Configuration
|
96
|
+
|
97
|
+
### servly.yml
|
98
|
+
|
99
|
+
The `servly.yml` file supports two formats:
|
100
|
+
|
101
|
+
1. **Simple format**:
|
102
|
+
```yaml
|
103
|
+
service-name: command to run
|
104
|
+
```
|
105
|
+
|
106
|
+
2. **Detailed format**:
|
107
|
+
```yaml
|
108
|
+
service-name:
|
109
|
+
cmd: command to run
|
110
|
+
cwd: working directory (optional)
|
111
|
+
env:
|
112
|
+
ENV_VAR1: value1
|
113
|
+
ENV_VAR2: value2
|
114
|
+
```
|
115
|
+
|
116
|
+
**Note**: The name "servly" is reserved and cannot be used as a service name.
|
117
|
+
|
118
|
+
### Directory Structure
|
119
|
+
|
120
|
+
Servly creates a `.servly` directory to store runtime information:
|
121
|
+
|
122
|
+
```
|
123
|
+
.servly/
|
124
|
+
├── logs/
|
125
|
+
│ ├── [service-name]-out.log # Standard output logs
|
126
|
+
│ └── [service-name]-error.log # Error logs
|
127
|
+
├── pids/
|
128
|
+
│ └── [service-name].pid # Process ID files
|
129
|
+
```
|
130
|
+
|
131
|
+
## License
|
132
|
+
|
133
|
+
MIT
|
servly-0.2.0/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# SERVLY
|
2
|
+
|
3
|
+
A simple process management tool for Linux, similar to PM2, designed to simplify application deployment and management.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Start, stop, and restart services defined in a `servly.yml` configuration file
|
8
|
+
- View real-time logs with service name highlighting
|
9
|
+
- Automatic process supervision and PID management
|
10
|
+
- Environment variable support
|
11
|
+
- Simple YAML configuration
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
```bash
|
16
|
+
# Using pip
|
17
|
+
pip install servly
|
18
|
+
|
19
|
+
# From source
|
20
|
+
git clone https://github.com/yourusername/servly.git
|
21
|
+
cd servly
|
22
|
+
pip install -e .
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Quick Start
|
28
|
+
|
29
|
+
1. Create a `servly.yml` file in your project:
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
# Basic format: service-name: command
|
33
|
+
web-server: node server.js
|
34
|
+
|
35
|
+
# Detailed format
|
36
|
+
api:
|
37
|
+
cmd: python api.py
|
38
|
+
cwd: ./api
|
39
|
+
env:
|
40
|
+
NODE_ENV: production
|
41
|
+
```
|
42
|
+
|
43
|
+
2. Start your services:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
servly start
|
47
|
+
```
|
48
|
+
|
49
|
+
### Core Commands
|
50
|
+
|
51
|
+
- **Start Services**:
|
52
|
+
```bash
|
53
|
+
servly start [all | service-name]
|
54
|
+
```
|
55
|
+
Starts all services or a specific service by name.
|
56
|
+
|
57
|
+
- **Stop Services**:
|
58
|
+
```bash
|
59
|
+
servly stop [all | service-name]
|
60
|
+
```
|
61
|
+
Stops all running services or a specific service by name.
|
62
|
+
|
63
|
+
- **Restart Services**:
|
64
|
+
```bash
|
65
|
+
servly restart [all | service-name]
|
66
|
+
```
|
67
|
+
Restarts all services or a specific service by name.
|
68
|
+
|
69
|
+
- **View Service Logs**:
|
70
|
+
```bash
|
71
|
+
servly log [all | service-name]
|
72
|
+
```
|
73
|
+
Shows logs in real-time (similar to `tail -f`).
|
74
|
+
|
75
|
+
- **List Services**:
|
76
|
+
```bash
|
77
|
+
servly list
|
78
|
+
```
|
79
|
+
Shows status of all configured services.
|
80
|
+
|
81
|
+
## Configuration
|
82
|
+
|
83
|
+
### servly.yml
|
84
|
+
|
85
|
+
The `servly.yml` file supports two formats:
|
86
|
+
|
87
|
+
1. **Simple format**:
|
88
|
+
```yaml
|
89
|
+
service-name: command to run
|
90
|
+
```
|
91
|
+
|
92
|
+
2. **Detailed format**:
|
93
|
+
```yaml
|
94
|
+
service-name:
|
95
|
+
cmd: command to run
|
96
|
+
cwd: working directory (optional)
|
97
|
+
env:
|
98
|
+
ENV_VAR1: value1
|
99
|
+
ENV_VAR2: value2
|
100
|
+
```
|
101
|
+
|
102
|
+
**Note**: The name "servly" is reserved and cannot be used as a service name.
|
103
|
+
|
104
|
+
### Directory Structure
|
105
|
+
|
106
|
+
Servly creates a `.servly` directory to store runtime information:
|
107
|
+
|
108
|
+
```
|
109
|
+
.servly/
|
110
|
+
├── logs/
|
111
|
+
│ ├── [service-name]-out.log # Standard output logs
|
112
|
+
│ └── [service-name]-error.log # Error logs
|
113
|
+
├── pids/
|
114
|
+
│ └── [service-name].pid # Process ID files
|
115
|
+
```
|
116
|
+
|
117
|
+
## License
|
118
|
+
|
119
|
+
MIT
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "servly"
|
7
|
-
version = "0.
|
7
|
+
version = "0.2.0"
|
8
8
|
description = "simple process manager"
|
9
9
|
readme = "README.md"
|
10
10
|
requires-python = ">=3.12"
|
@@ -18,9 +18,17 @@ classifiers = [
|
|
18
18
|
"License :: OSI Approved :: MIT License",
|
19
19
|
"Operating System :: OS Independent",
|
20
20
|
]
|
21
|
+
dependencies = [
|
22
|
+
"pyyaml>=6.0.2",
|
23
|
+
]
|
21
24
|
|
22
25
|
[project.scripts]
|
23
|
-
|
26
|
+
servly = "servly.cli:main"
|
24
27
|
|
25
28
|
[tool.setuptools.packages.find]
|
26
|
-
include = ["
|
29
|
+
include = ["servly*"]
|
30
|
+
|
31
|
+
[dependency-groups]
|
32
|
+
dev = [
|
33
|
+
"pytest>=8.3.5",
|
34
|
+
]
|
@@ -0,0 +1,295 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Command-line interface for Servly process manager.
|
4
|
+
"""
|
5
|
+
import os
|
6
|
+
import sys
|
7
|
+
import argparse
|
8
|
+
import logging
|
9
|
+
from pathlib import Path
|
10
|
+
from typing import List, Optional
|
11
|
+
|
12
|
+
from servly.service import ServiceManager
|
13
|
+
from servly.logs import LogManager
|
14
|
+
from servly.logs import Colors, Emojis # 导入颜色和表情符号定义
|
15
|
+
from servly.logs import align_colored_text # 导入对齐工具函数
|
16
|
+
|
17
|
+
# 配置彩色日志记录器
|
18
|
+
class ColoredFormatter(logging.Formatter):
|
19
|
+
"""添加颜色支持的日志格式化器"""
|
20
|
+
|
21
|
+
def format(self, record):
|
22
|
+
log_message = super().format(record)
|
23
|
+
|
24
|
+
if record.levelno >= logging.ERROR:
|
25
|
+
return f"{Emojis.ERROR} {Colors.BRIGHT_RED}{log_message}{Colors.RESET}"
|
26
|
+
elif record.levelno >= logging.WARNING:
|
27
|
+
return f"{Emojis.WARNING} {Colors.YELLOW}{log_message}{Colors.RESET}"
|
28
|
+
elif record.levelno >= logging.INFO:
|
29
|
+
return f"{Emojis.INFO} {Colors.GREEN}{log_message}{Colors.RESET}"
|
30
|
+
else:
|
31
|
+
return f"{Colors.BRIGHT_BLACK}{log_message}{Colors.RESET}"
|
32
|
+
|
33
|
+
# 配置日志
|
34
|
+
handler = logging.StreamHandler()
|
35
|
+
handler.setFormatter(ColoredFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
36
|
+
logger = logging.getLogger('servly')
|
37
|
+
logger.setLevel(logging.INFO)
|
38
|
+
logger.addHandler(handler)
|
39
|
+
|
40
|
+
def print_header():
|
41
|
+
"""打印美化的 Servly 头部"""
|
42
|
+
print(f"\n{Colors.CYAN}{Colors.BOLD}{'=' * 50}")
|
43
|
+
print(f"{Emojis.SERVICE} SERVLY {Colors.BRIGHT_BLACK}- Modern Process Manager")
|
44
|
+
print(f"{Colors.CYAN}{'=' * 50}{Colors.RESET}\n")
|
45
|
+
|
46
|
+
def setup_arg_parser() -> argparse.ArgumentParser:
|
47
|
+
"""设置命令行参数解析器"""
|
48
|
+
parser = argparse.ArgumentParser(
|
49
|
+
description=f"{Colors.CYAN}{Colors.BOLD}{Emojis.SERVICE} Servly - Modern process manager{Colors.RESET}",
|
50
|
+
formatter_class=argparse.RawDescriptionHelpFormatter
|
51
|
+
)
|
52
|
+
|
53
|
+
# 全局参数
|
54
|
+
parser.add_argument('-f', '--config',
|
55
|
+
help='配置文件路径 (默认: servly.yml)',
|
56
|
+
default='servly.yml')
|
57
|
+
|
58
|
+
subparsers = parser.add_subparsers(dest='command', help='要执行的命令')
|
59
|
+
|
60
|
+
# Start 命令
|
61
|
+
start_parser = subparsers.add_parser('start', help=f'{Emojis.START} 启动服务')
|
62
|
+
start_parser.add_argument('service', nargs='?', default='all',
|
63
|
+
help='服务名称或 "all" 启动所有服务')
|
64
|
+
|
65
|
+
# Stop 命令
|
66
|
+
stop_parser = subparsers.add_parser('stop', help=f'{Emojis.STOP} 停止服务')
|
67
|
+
stop_parser.add_argument('service', nargs='?', default='all',
|
68
|
+
help='服务名称或 "all" 停止所有服务')
|
69
|
+
|
70
|
+
# Restart 命令
|
71
|
+
restart_parser = subparsers.add_parser('restart', help=f'{Emojis.RESTART} 重启服务')
|
72
|
+
restart_parser.add_argument('service', nargs='?', default='all',
|
73
|
+
help='服务名称或 "all" 重启所有服务')
|
74
|
+
|
75
|
+
# Log 命令
|
76
|
+
log_parser = subparsers.add_parser('log', help=f'{Emojis.LOG} 查看服务日志')
|
77
|
+
log_parser.add_argument('service', nargs='?', default='all',
|
78
|
+
help='服务名称或 "all" 查看所有日志')
|
79
|
+
log_parser.add_argument('--no-follow', '-n', action='store_true',
|
80
|
+
help='不实时跟踪日志')
|
81
|
+
log_parser.add_argument('--lines', '-l', type=int, default=10,
|
82
|
+
help='初始显示的行数')
|
83
|
+
|
84
|
+
# List 命令 - 保留原命令名,不改为 ps
|
85
|
+
list_parser = subparsers.add_parser('list', help='列出服务')
|
86
|
+
|
87
|
+
return parser
|
88
|
+
|
89
|
+
def handle_start(manager: ServiceManager, service_name: str) -> bool:
|
90
|
+
"""处理启动命令"""
|
91
|
+
if service_name == 'all':
|
92
|
+
service_names = manager.get_service_names()
|
93
|
+
if not service_names:
|
94
|
+
print(f"{Emojis.WARNING} {Colors.YELLOW}配置中没有定义任何服务。{Colors.RESET}")
|
95
|
+
return False
|
96
|
+
|
97
|
+
print(f"{Emojis.START} {Colors.BRIGHT_GREEN}正在启动所有服务...{Colors.RESET}")
|
98
|
+
success = True
|
99
|
+
for name in service_names:
|
100
|
+
if not manager.start(name):
|
101
|
+
print(f"{Emojis.ERROR} {Colors.RED}启动服务 '{name}' 失败{Colors.RESET}")
|
102
|
+
success = False
|
103
|
+
else:
|
104
|
+
print(f"{Emojis.RUNNING} {Colors.GREEN}服务 '{name}' 已成功启动{Colors.RESET}")
|
105
|
+
|
106
|
+
if success:
|
107
|
+
print(f"\n{Emojis.RUNNING} {Colors.BRIGHT_GREEN}所有服务已成功启动!{Colors.RESET}")
|
108
|
+
else:
|
109
|
+
print(f"\n{Emojis.WARNING} {Colors.YELLOW}有些服务启动失败,请检查日志获取详情。{Colors.RESET}")
|
110
|
+
|
111
|
+
return success
|
112
|
+
else:
|
113
|
+
result = manager.start(service_name)
|
114
|
+
if result:
|
115
|
+
print(f"{Emojis.RUNNING} {Colors.GREEN}服务 '{service_name}' 已成功启动{Colors.RESET}")
|
116
|
+
else:
|
117
|
+
print(f"{Emojis.ERROR} {Colors.RED}启动服务 '{service_name}' 失败{Colors.RESET}")
|
118
|
+
return result
|
119
|
+
|
120
|
+
def handle_stop(manager: ServiceManager, service_name: str) -> bool:
|
121
|
+
"""处理停止命令"""
|
122
|
+
if service_name == 'all':
|
123
|
+
service_names = manager.get_running_services()
|
124
|
+
if not service_names:
|
125
|
+
print(f"{Emojis.INFO} {Colors.BRIGHT_BLACK}当前没有正在运行的服务。{Colors.RESET}")
|
126
|
+
return True
|
127
|
+
|
128
|
+
print(f"{Emojis.STOP} {Colors.YELLOW}正在停止所有服务...{Colors.RESET}")
|
129
|
+
success = True
|
130
|
+
for name in service_names:
|
131
|
+
if not manager.stop(name):
|
132
|
+
print(f"{Emojis.ERROR} {Colors.RED}停止服务 '{name}' 失败{Colors.RESET}")
|
133
|
+
success = False
|
134
|
+
else:
|
135
|
+
print(f"{Emojis.STOPPED} {Colors.YELLOW}服务 '{name}' 已停止{Colors.RESET}")
|
136
|
+
|
137
|
+
if success:
|
138
|
+
print(f"\n{Emojis.STOPPED} {Colors.YELLOW}所有服务已成功停止!{Colors.RESET}")
|
139
|
+
else:
|
140
|
+
print(f"\n{Emojis.WARNING} {Colors.YELLOW}有些服务停止失败,请检查日志获取详情。{Colors.RESET}")
|
141
|
+
|
142
|
+
return success
|
143
|
+
else:
|
144
|
+
result = manager.stop(service_name)
|
145
|
+
if result:
|
146
|
+
print(f"{Emojis.STOPPED} {Colors.YELLOW}服务 '{service_name}' 已成功停止{Colors.RESET}")
|
147
|
+
else:
|
148
|
+
print(f"{Emojis.ERROR} {Colors.RED}停止服务 '{service_name}' 失败{Colors.RESET}")
|
149
|
+
return result
|
150
|
+
|
151
|
+
def handle_restart(manager: ServiceManager, service_name: str) -> bool:
|
152
|
+
"""处理重启命令"""
|
153
|
+
if service_name == 'all':
|
154
|
+
service_names = manager.get_service_names()
|
155
|
+
if not service_names:
|
156
|
+
print(f"{Emojis.WARNING} {Colors.YELLOW}配置中没有定义任何服务。{Colors.RESET}")
|
157
|
+
return False
|
158
|
+
|
159
|
+
print(f"{Emojis.RESTART} {Colors.MAGENTA}正在重启所有服务...{Colors.RESET}")
|
160
|
+
success = True
|
161
|
+
for name in service_names:
|
162
|
+
if not manager.restart(name):
|
163
|
+
print(f"{Emojis.ERROR} {Colors.RED}重启服务 '{name}' 失败{Colors.RESET}")
|
164
|
+
success = False
|
165
|
+
else:
|
166
|
+
print(f"{Emojis.RUNNING} {Colors.MAGENTA}服务 '{name}' 已成功重启{Colors.RESET}")
|
167
|
+
|
168
|
+
if success:
|
169
|
+
print(f"\n{Emojis.RUNNING} {Colors.BRIGHT_GREEN}所有服务已成功重启!{Colors.RESET}")
|
170
|
+
else:
|
171
|
+
print(f"\n{Emojis.WARNING} {Colors.YELLOW}有些服务重启失败,请检查日志获取详情。{Colors.RESET}")
|
172
|
+
|
173
|
+
return success
|
174
|
+
else:
|
175
|
+
result = manager.restart(service_name)
|
176
|
+
if result:
|
177
|
+
print(f"{Emojis.RUNNING} {Colors.MAGENTA}服务 '{service_name}' 已成功重启{Colors.RESET}")
|
178
|
+
else:
|
179
|
+
print(f"{Emojis.ERROR} {Colors.RED}重启服务 '{service_name}' 失败{Colors.RESET}")
|
180
|
+
return result
|
181
|
+
|
182
|
+
def handle_log(manager: ServiceManager, log_manager: LogManager, args) -> bool:
|
183
|
+
"""处理日志查看命令"""
|
184
|
+
service_name = args.service
|
185
|
+
follow = not args.no_follow
|
186
|
+
lines = args.lines
|
187
|
+
|
188
|
+
if service_name == 'all':
|
189
|
+
services = manager.get_service_names()
|
190
|
+
if not services:
|
191
|
+
print(f"{Emojis.WARNING} {Colors.YELLOW}配置中没有定义任何服务。{Colors.RESET}")
|
192
|
+
return False
|
193
|
+
else:
|
194
|
+
if service_name not in manager.get_service_names():
|
195
|
+
print(f"{Emojis.ERROR} {Colors.RED}服务 '{service_name}' 在配置中未找到。{Colors.RESET}")
|
196
|
+
return False
|
197
|
+
services = [service_name]
|
198
|
+
|
199
|
+
# 已经在 LogManager 中添加了彩色输出
|
200
|
+
log_manager.tail_logs(services, follow=follow, lines=lines)
|
201
|
+
return True
|
202
|
+
|
203
|
+
def handle_list(manager: ServiceManager) -> bool:
|
204
|
+
"""处理列出服务命令"""
|
205
|
+
service_names = manager.get_service_names()
|
206
|
+
|
207
|
+
if not service_names:
|
208
|
+
print(f"{Emojis.WARNING} {Colors.YELLOW}配置中没有定义任何服务。{Colors.RESET}")
|
209
|
+
return True
|
210
|
+
|
211
|
+
# 表头
|
212
|
+
print(f"\n{Colors.CYAN}{Colors.BOLD}{Emojis.SERVICE} 服务列表{Colors.RESET}")
|
213
|
+
print(f"{Colors.CYAN}{'─' * 60}{Colors.RESET}")
|
214
|
+
|
215
|
+
# 列标题
|
216
|
+
print(f"{Colors.BOLD}{align_colored_text(' 名称', 25)} {align_colored_text('状态', 20)} {align_colored_text('PID', 10)}{Colors.RESET}")
|
217
|
+
print(f"{Colors.BRIGHT_BLACK}{'─' * 60}{Colors.RESET}")
|
218
|
+
|
219
|
+
# 服务列表
|
220
|
+
for name in service_names:
|
221
|
+
is_running = manager.is_running(name)
|
222
|
+
pid = manager.get_service_pid(name) or '-'
|
223
|
+
|
224
|
+
if is_running:
|
225
|
+
status_text = f"{Emojis.RUNNING} {Colors.GREEN}RUNNING{Colors.RESET}"
|
226
|
+
pid_text = f"{Colors.GREEN}{pid}{Colors.RESET}"
|
227
|
+
else:
|
228
|
+
status_text = f"{Emojis.STOPPED} {Colors.BRIGHT_BLACK}STOPPED{Colors.RESET}"
|
229
|
+
pid_text = f"{Colors.BRIGHT_BLACK}{pid}{Colors.RESET}"
|
230
|
+
|
231
|
+
# 为不同服务使用不同颜色
|
232
|
+
service_color = Colors.CYAN if is_running else Colors.BRIGHT_BLACK
|
233
|
+
service_text = f"{service_color}{name}{Colors.RESET}"
|
234
|
+
|
235
|
+
# 使用对齐辅助函数确保正确对齐包含颜色代码的文本
|
236
|
+
aligned_service = align_colored_text(f" {service_text}", 25)
|
237
|
+
aligned_status = align_colored_text(status_text, 20)
|
238
|
+
aligned_pid = align_colored_text(pid_text, 10)
|
239
|
+
|
240
|
+
print(f"{aligned_service}{aligned_status}{aligned_pid}")
|
241
|
+
|
242
|
+
print(f"\n{Colors.BRIGHT_BLACK}配置文件: {manager.config_path}{Colors.RESET}")
|
243
|
+
print(f"{Colors.BRIGHT_BLACK}运行中服务: {len(manager.get_running_services())}/{len(service_names)}{Colors.RESET}")
|
244
|
+
print()
|
245
|
+
|
246
|
+
return True
|
247
|
+
|
248
|
+
def main():
|
249
|
+
"""CLI 应用程序入口点"""
|
250
|
+
# 显示头部
|
251
|
+
print_header()
|
252
|
+
|
253
|
+
parser = setup_arg_parser()
|
254
|
+
args = parser.parse_args()
|
255
|
+
|
256
|
+
if not args.command:
|
257
|
+
parser.print_help()
|
258
|
+
return 1
|
259
|
+
|
260
|
+
# 创建服务管理器
|
261
|
+
try:
|
262
|
+
service_manager = ServiceManager(config_path=args.config)
|
263
|
+
except Exception as e:
|
264
|
+
print(f"{Emojis.ERROR} {Colors.RED}加载配置文件时出错: {e}{Colors.RESET}")
|
265
|
+
return 1
|
266
|
+
|
267
|
+
# 创建日志管理器
|
268
|
+
log_manager = LogManager(service_manager.log_dir)
|
269
|
+
|
270
|
+
# 处理命令
|
271
|
+
try:
|
272
|
+
if args.command == 'start':
|
273
|
+
success = handle_start(service_manager, args.service)
|
274
|
+
elif args.command == 'stop':
|
275
|
+
success = handle_stop(service_manager, args.service)
|
276
|
+
elif args.command == 'restart':
|
277
|
+
success = handle_restart(service_manager, args.service)
|
278
|
+
elif args.command == 'log':
|
279
|
+
success = handle_log(service_manager, log_manager, args)
|
280
|
+
elif args.command == 'list':
|
281
|
+
success = handle_list(service_manager)
|
282
|
+
else:
|
283
|
+
parser.print_help()
|
284
|
+
return 1
|
285
|
+
except KeyboardInterrupt:
|
286
|
+
print(f"\n{Emojis.STOP} {Colors.BRIGHT_BLACK}操作被用户中断{Colors.RESET}")
|
287
|
+
return 1
|
288
|
+
except Exception as e:
|
289
|
+
print(f"\n{Emojis.ERROR} {Colors.RED}执行命令时出错: {e}{Colors.RESET}")
|
290
|
+
return 1
|
291
|
+
|
292
|
+
return 0 if success else 1
|
293
|
+
|
294
|
+
if __name__ == "__main__":
|
295
|
+
sys.exit(main())
|