python-dmon 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.
- python_dmon-0.2.0/PKG-INFO +156 -0
- python_dmon-0.2.0/README.md +138 -0
- python_dmon-0.2.0/pyproject.toml +37 -0
- python_dmon-0.2.0/src/dmon/__init__.py +0 -0
- python_dmon-0.2.0/src/dmon/__main__.py +5 -0
- python_dmon-0.2.0/src/dmon/cli.py +232 -0
- python_dmon-0.2.0/src/dmon/config.py +195 -0
- python_dmon-0.2.0/src/dmon/constants.py +14 -0
- python_dmon-0.2.0/src/dmon/control.py +542 -0
- python_dmon-0.2.0/src/dmon/py.typed +0 -0
- python_dmon-0.2.0/src/dmon/runner.py +188 -0
- python_dmon-0.2.0/src/dmon/types.py +63 -0
- python_dmon-0.2.0/src/dmon/utils.py +32 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: python-dmon
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A lightweight, cross-platform daemon manager that runs any command as a background process.
|
|
5
|
+
Keywords: python-dmon,dmon,daemon,background,detach,process management
|
|
6
|
+
Author: Atomie CHEN
|
|
7
|
+
Author-email: Atomie CHEN <atomic_cwh@163.com>
|
|
8
|
+
Requires-Dist: colorama>=0.4.6
|
|
9
|
+
Requires-Dist: psutil>=7.1.0
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
11
|
+
Requires-Dist: termcolor>=2.4.0
|
|
12
|
+
Requires-Dist: tomli>=2.2.1 ; python_full_version < '3.11'
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Project-URL: Bug Tracker, https://github.com/atomiechen/python-dmon/issues
|
|
15
|
+
Project-URL: Changelog, https://github.com/atomiechen/python-dmon/blob/master/CHANGELOG.md
|
|
16
|
+
Project-URL: Homepage, https://github.com/atomiechen/python-dmon
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# python-dmon
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
[](https://github.com/atomiechen/python-dmon)
|
|
23
|
+
[](https://pypi.org/project/python-dmon/)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
A lightweight, cross-platform daemon manager that runs any command — called a *task* — as a background process.
|
|
27
|
+
It also supports logging and log rotation out of the box.
|
|
28
|
+
**No Docker or extra dependencies required**.
|
|
29
|
+
|
|
30
|
+
Shipped as the CLI tool `dmon`.
|
|
31
|
+
It is a Python-based and more powerful successor to the [handy-backend shell scripts](https://github.com/atomiechen/handy-backend).
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- 🖥️ **Cross-platform:** Works on Linux, macOS, and Windows.
|
|
37
|
+
- ⚡ **Lightweight:** Pure Python, no Docker or external dependencies needed.
|
|
38
|
+
- 🧩 **Flexible tasks:** Tasks can be configured in `pyproject.toml` or `dmon.yaml`; or run ad-hoc commands directly.
|
|
39
|
+
- 🪵 **Logging & log rotation:** Automatically manage log files to prevent uncontrolled growth.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
pip install python-dmon
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To get the latest features, install from source:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
pip install git+https://github.com/atomiechen/python-dmon.git
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Getting Started
|
|
55
|
+
|
|
56
|
+
### Prepare Configuration
|
|
57
|
+
|
|
58
|
+
Create a `dmon.yaml` file:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
tasks:
|
|
62
|
+
app: ["python", "-u", "server.py"]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or add to your `pyproject.toml`:
|
|
66
|
+
|
|
67
|
+
```toml
|
|
68
|
+
[tool.dmon.tasks]
|
|
69
|
+
app = ["python", "-u", "server.py"]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Commands can be a single string (run in shell), or list of strings (exec form).
|
|
73
|
+
See [Example Task Configuration](#example-task-configuration) for more configuration options.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Run tasks
|
|
77
|
+
|
|
78
|
+
Run a configured task by its name:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
# Start a task
|
|
82
|
+
dmon start app
|
|
83
|
+
|
|
84
|
+
# Stop a running task
|
|
85
|
+
dmon stop app
|
|
86
|
+
|
|
87
|
+
# Check task status
|
|
88
|
+
dmon status app
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If only one task is defined in the config file, you can omit the task name:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
dmon start
|
|
95
|
+
dmon stop
|
|
96
|
+
dmon status
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
### Run an ad-hoc command
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
# Run a command with arguments in the background
|
|
104
|
+
dmon run --name myserver python -u server.py
|
|
105
|
+
|
|
106
|
+
# Run a shell command in the background
|
|
107
|
+
dmon run --shell echo "Hello World"
|
|
108
|
+
|
|
109
|
+
# Run a shell script in the background
|
|
110
|
+
dmon run --cwd /path/to/script bash myscript.sh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
> [!NOTE]
|
|
114
|
+
> If no name is provided, `dmon` automatically assigns a fixed task name `default_run` to prevent duplicate runs.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
### List all running tasks
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
dmon list
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Example Task Configuration
|
|
125
|
+
|
|
126
|
+
A task can be a **string**, **list**, or **dictionary**.
|
|
127
|
+
|
|
128
|
+
Here is a more complete example with default values:
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
tasks:
|
|
132
|
+
your_task_name:
|
|
133
|
+
# Command to run; can be a string (run in shell) or list of strings (exec form)
|
|
134
|
+
cmd: ["python", "server.py"] # required
|
|
135
|
+
cwd: "/path/to/working/dir" # (default: current dir)
|
|
136
|
+
env: # (default: inherit from parent process)
|
|
137
|
+
PYTHONUNBUFFERED: "1"
|
|
138
|
+
override_env: false # override parent env and only use env defined here
|
|
139
|
+
log_path: "logs/<name>.log" # path to log file
|
|
140
|
+
log_rotate: false # enable log rotation
|
|
141
|
+
log_max_size: 5 # max log file size before rotation in MB
|
|
142
|
+
rotate_log_path: "logs/<name>.rotate.log" # path to rotation log
|
|
143
|
+
rotate_log_max_size: 5 # max rotation log file size in MB
|
|
144
|
+
meta_path: ".dmon/<name>.meta.json" # path to meta file
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Under the Hood
|
|
148
|
+
|
|
149
|
+
Each task is associated with a meta file (e.g. `.dmon/<name>.meta.json`) stored in the current working directory.
|
|
150
|
+
The file contains details such as the command, PID, log path, and more.
|
|
151
|
+
**Do not** modify or delete these files manually.
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
[python-dmon](https://github.com/atomiechen/python-dmon) © 2025 by [Atomie CHEN](https://github.com/atomiechen) is licensed under the [MIT License](https://github.com/atomiechen/python-dmon/blob/main/LICENSE).
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# python-dmon
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[](https://github.com/atomiechen/python-dmon)
|
|
5
|
+
[](https://pypi.org/project/python-dmon/)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
A lightweight, cross-platform daemon manager that runs any command — called a *task* — as a background process.
|
|
9
|
+
It also supports logging and log rotation out of the box.
|
|
10
|
+
**No Docker or extra dependencies required**.
|
|
11
|
+
|
|
12
|
+
Shipped as the CLI tool `dmon`.
|
|
13
|
+
It is a Python-based and more powerful successor to the [handy-backend shell scripts](https://github.com/atomiechen/handy-backend).
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- 🖥️ **Cross-platform:** Works on Linux, macOS, and Windows.
|
|
19
|
+
- ⚡ **Lightweight:** Pure Python, no Docker or external dependencies needed.
|
|
20
|
+
- 🧩 **Flexible tasks:** Tasks can be configured in `pyproject.toml` or `dmon.yaml`; or run ad-hoc commands directly.
|
|
21
|
+
- 🪵 **Logging & log rotation:** Automatically manage log files to prevent uncontrolled growth.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
pip install python-dmon
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
To get the latest features, install from source:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pip install git+https://github.com/atomiechen/python-dmon.git
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Getting Started
|
|
37
|
+
|
|
38
|
+
### Prepare Configuration
|
|
39
|
+
|
|
40
|
+
Create a `dmon.yaml` file:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
tasks:
|
|
44
|
+
app: ["python", "-u", "server.py"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or add to your `pyproject.toml`:
|
|
48
|
+
|
|
49
|
+
```toml
|
|
50
|
+
[tool.dmon.tasks]
|
|
51
|
+
app = ["python", "-u", "server.py"]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Commands can be a single string (run in shell), or list of strings (exec form).
|
|
55
|
+
See [Example Task Configuration](#example-task-configuration) for more configuration options.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Run tasks
|
|
59
|
+
|
|
60
|
+
Run a configured task by its name:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
# Start a task
|
|
64
|
+
dmon start app
|
|
65
|
+
|
|
66
|
+
# Stop a running task
|
|
67
|
+
dmon stop app
|
|
68
|
+
|
|
69
|
+
# Check task status
|
|
70
|
+
dmon status app
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If only one task is defined in the config file, you can omit the task name:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
dmon start
|
|
77
|
+
dmon stop
|
|
78
|
+
dmon status
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
### Run an ad-hoc command
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
# Run a command with arguments in the background
|
|
86
|
+
dmon run --name myserver python -u server.py
|
|
87
|
+
|
|
88
|
+
# Run a shell command in the background
|
|
89
|
+
dmon run --shell echo "Hello World"
|
|
90
|
+
|
|
91
|
+
# Run a shell script in the background
|
|
92
|
+
dmon run --cwd /path/to/script bash myscript.sh
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> [!NOTE]
|
|
96
|
+
> If no name is provided, `dmon` automatically assigns a fixed task name `default_run` to prevent duplicate runs.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
### List all running tasks
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
dmon list
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## Example Task Configuration
|
|
107
|
+
|
|
108
|
+
A task can be a **string**, **list**, or **dictionary**.
|
|
109
|
+
|
|
110
|
+
Here is a more complete example with default values:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
tasks:
|
|
114
|
+
your_task_name:
|
|
115
|
+
# Command to run; can be a string (run in shell) or list of strings (exec form)
|
|
116
|
+
cmd: ["python", "server.py"] # required
|
|
117
|
+
cwd: "/path/to/working/dir" # (default: current dir)
|
|
118
|
+
env: # (default: inherit from parent process)
|
|
119
|
+
PYTHONUNBUFFERED: "1"
|
|
120
|
+
override_env: false # override parent env and only use env defined here
|
|
121
|
+
log_path: "logs/<name>.log" # path to log file
|
|
122
|
+
log_rotate: false # enable log rotation
|
|
123
|
+
log_max_size: 5 # max log file size before rotation in MB
|
|
124
|
+
rotate_log_path: "logs/<name>.rotate.log" # path to rotation log
|
|
125
|
+
rotate_log_max_size: 5 # max rotation log file size in MB
|
|
126
|
+
meta_path: ".dmon/<name>.meta.json" # path to meta file
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Under the Hood
|
|
130
|
+
|
|
131
|
+
Each task is associated with a meta file (e.g. `.dmon/<name>.meta.json`) stored in the current working directory.
|
|
132
|
+
The file contains details such as the command, PID, log path, and more.
|
|
133
|
+
**Do not** modify or delete these files manually.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
[python-dmon](https://github.com/atomiechen/python-dmon) © 2025 by [Atomie CHEN](https://github.com/atomiechen) is licensed under the [MIT License](https://github.com/atomiechen/python-dmon/blob/main/LICENSE).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "python-dmon"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "A lightweight, cross-platform daemon manager that runs any command as a background process."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Atomie CHEN", email = "atomic_cwh@163.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"colorama>=0.4.6",
|
|
12
|
+
"psutil>=7.1.0",
|
|
13
|
+
"pyyaml>=6.0.3",
|
|
14
|
+
"termcolor>=2.4.0",
|
|
15
|
+
"tomli>=2.2.1 ; python_full_version < '3.11'",
|
|
16
|
+
]
|
|
17
|
+
keywords = ["python-dmon", "dmon", "daemon", "background", "detach", "process management"]
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
"Homepage" = "https://github.com/atomiechen/python-dmon"
|
|
21
|
+
"Bug Tracker" = "https://github.com/atomiechen/python-dmon/issues"
|
|
22
|
+
Changelog = "https://github.com/atomiechen/python-dmon/blob/master/CHANGELOG.md"
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
dmon = "dmon.__main__:main"
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = ["uv_build>=0.8.4,<0.9.0"]
|
|
29
|
+
build-backend = "uv_build"
|
|
30
|
+
|
|
31
|
+
[tool.uv.build-backend]
|
|
32
|
+
module-name = "dmon"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"ruff>=0.13.3",
|
|
37
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import shlex
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from colorama import just_fix_windows_console
|
|
6
|
+
|
|
7
|
+
from .config import check_name_in_config, get_task_config
|
|
8
|
+
from .control import list_processes, restart, start, stop, status
|
|
9
|
+
from .constants import (
|
|
10
|
+
DEFAULT_META_DIR,
|
|
11
|
+
DEFAULT_RUN_NAME,
|
|
12
|
+
LOG_PATH_TEMPLATE,
|
|
13
|
+
META_PATH_TEMPLATE,
|
|
14
|
+
ROTATE_LOG_PATH_TEMPLATE,
|
|
15
|
+
)
|
|
16
|
+
from .types import DmonTaskConfig
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
just_fix_windows_console()
|
|
21
|
+
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
prog="dmon",
|
|
24
|
+
description="Minimal cross-platform daemon manager",
|
|
25
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
26
|
+
)
|
|
27
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
28
|
+
|
|
29
|
+
# start subcommand
|
|
30
|
+
sp_start = subparsers.add_parser(
|
|
31
|
+
"start",
|
|
32
|
+
help="Start a configured task as a background process",
|
|
33
|
+
description="Start a configured task as a background process",
|
|
34
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
35
|
+
)
|
|
36
|
+
sp_start.add_argument(
|
|
37
|
+
"name",
|
|
38
|
+
help="Configured task name (default: the only task if there's just one)",
|
|
39
|
+
nargs="?",
|
|
40
|
+
)
|
|
41
|
+
sp_start.add_argument(
|
|
42
|
+
"--meta-file",
|
|
43
|
+
help=f"Path to meta file (default: {META_PATH_TEMPLATE})",
|
|
44
|
+
)
|
|
45
|
+
sp_start.add_argument(
|
|
46
|
+
"--log-file",
|
|
47
|
+
help=f"Path to log file (default: task configured or {LOG_PATH_TEMPLATE})",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# stop subcommand
|
|
51
|
+
sp_stop = subparsers.add_parser(
|
|
52
|
+
"stop",
|
|
53
|
+
help="Stop a background process",
|
|
54
|
+
description="Stop a background process given name or meta file",
|
|
55
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
56
|
+
)
|
|
57
|
+
sp_stop.add_argument(
|
|
58
|
+
"name",
|
|
59
|
+
help="Configured task name (default: the only task if there's just one)",
|
|
60
|
+
nargs="?",
|
|
61
|
+
)
|
|
62
|
+
sp_stop.add_argument("--meta-file", help="Path to meta file")
|
|
63
|
+
|
|
64
|
+
# restart subcommand
|
|
65
|
+
sp_restart = subparsers.add_parser(
|
|
66
|
+
"restart",
|
|
67
|
+
help="Restart a configured task as a background process",
|
|
68
|
+
description="Restart a configured task as a background process",
|
|
69
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
70
|
+
)
|
|
71
|
+
sp_restart.add_argument(
|
|
72
|
+
"name",
|
|
73
|
+
help="Configured task name (default: the only task if there's just one)",
|
|
74
|
+
nargs="?",
|
|
75
|
+
)
|
|
76
|
+
sp_restart.add_argument(
|
|
77
|
+
"--meta-file",
|
|
78
|
+
help=f"Path to meta file (default: {META_PATH_TEMPLATE})",
|
|
79
|
+
)
|
|
80
|
+
sp_restart.add_argument(
|
|
81
|
+
"--log-file",
|
|
82
|
+
help=f"Path to log file (default: task configured or {LOG_PATH_TEMPLATE})",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# status subcommand
|
|
86
|
+
sp_status = subparsers.add_parser(
|
|
87
|
+
"status",
|
|
88
|
+
help="Check process status",
|
|
89
|
+
description="Check status of a background process given name or meta file",
|
|
90
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
91
|
+
)
|
|
92
|
+
sp_status.add_argument(
|
|
93
|
+
"name",
|
|
94
|
+
help="Configured task name (default: the only task if there's just one)",
|
|
95
|
+
nargs="?",
|
|
96
|
+
)
|
|
97
|
+
sp_status.add_argument(
|
|
98
|
+
"--meta-file",
|
|
99
|
+
help=f"Path to meta file (default: {META_PATH_TEMPLATE})",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# list subcommand
|
|
103
|
+
sp_list = subparsers.add_parser(
|
|
104
|
+
"list",
|
|
105
|
+
help="List all processes and their status",
|
|
106
|
+
description="List all processes and their status managed by dmon in the given directory",
|
|
107
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
108
|
+
)
|
|
109
|
+
sp_list.add_argument(
|
|
110
|
+
"dir",
|
|
111
|
+
help=f"Directory to look for meta files (default: {DEFAULT_META_DIR})",
|
|
112
|
+
nargs="?",
|
|
113
|
+
)
|
|
114
|
+
sp_list.add_argument(
|
|
115
|
+
"--full",
|
|
116
|
+
action="store_true",
|
|
117
|
+
help="Show full width without truncating column (default: False)",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# run subcommand
|
|
121
|
+
sp_run = subparsers.add_parser(
|
|
122
|
+
"run",
|
|
123
|
+
help="Run a custom task (not in config) as a background process",
|
|
124
|
+
description="Run a custom task (not in config) as a background process",
|
|
125
|
+
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
126
|
+
)
|
|
127
|
+
sp_run.add_argument(
|
|
128
|
+
"--name",
|
|
129
|
+
"-n",
|
|
130
|
+
default=DEFAULT_RUN_NAME,
|
|
131
|
+
help=f"Name for this task (default: {DEFAULT_RUN_NAME})",
|
|
132
|
+
)
|
|
133
|
+
sp_run.add_argument(
|
|
134
|
+
"--cwd",
|
|
135
|
+
help="Working directory to run the command in (default: current directory)",
|
|
136
|
+
default="",
|
|
137
|
+
)
|
|
138
|
+
sp_run.add_argument(
|
|
139
|
+
"--shell", action="store_true", help="Run task in shell (default: False)"
|
|
140
|
+
)
|
|
141
|
+
sp_run.add_argument(
|
|
142
|
+
"--meta-file",
|
|
143
|
+
help=f"Path to meta file (default: {META_PATH_TEMPLATE})",
|
|
144
|
+
)
|
|
145
|
+
sp_run.add_argument(
|
|
146
|
+
"--log-file",
|
|
147
|
+
help=f"Path to log file (default: {LOG_PATH_TEMPLATE})",
|
|
148
|
+
)
|
|
149
|
+
sp_run.add_argument(
|
|
150
|
+
"--log-rotate",
|
|
151
|
+
action="store_true",
|
|
152
|
+
help="Whether to rotate log file (default: False)",
|
|
153
|
+
)
|
|
154
|
+
sp_run.add_argument(
|
|
155
|
+
"--rotate-log-path",
|
|
156
|
+
help=f"Path to rotation log file (default: {ROTATE_LOG_PATH_TEMPLATE})",
|
|
157
|
+
)
|
|
158
|
+
sp_run.add_argument(
|
|
159
|
+
"command_list",
|
|
160
|
+
metavar="command",
|
|
161
|
+
nargs=argparse.ONE_OR_MORE,
|
|
162
|
+
help="Command (with args) to run",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
args = parser.parse_args()
|
|
166
|
+
|
|
167
|
+
if args.command in ["start", "restart"]:
|
|
168
|
+
sp = sp_start if args.command == "start" else sp_restart
|
|
169
|
+
try:
|
|
170
|
+
name, task_cfg = get_task_config(args.name)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
sp.error(str(e))
|
|
173
|
+
|
|
174
|
+
task_cfg.meta_path = (
|
|
175
|
+
args.meta_file or task_cfg.meta_path or META_PATH_TEMPLATE.format(name=name)
|
|
176
|
+
)
|
|
177
|
+
task_cfg.log_path = (
|
|
178
|
+
args.log_file or task_cfg.log_path or LOG_PATH_TEMPLATE.format(name=name)
|
|
179
|
+
)
|
|
180
|
+
task_cfg.rotate_log_path = (
|
|
181
|
+
task_cfg.rotate_log_path or ROTATE_LOG_PATH_TEMPLATE.format(name=name)
|
|
182
|
+
)
|
|
183
|
+
if args.command == "start":
|
|
184
|
+
sys.exit(start(task_cfg))
|
|
185
|
+
else:
|
|
186
|
+
sys.exit(restart(task_cfg))
|
|
187
|
+
elif args.command in ["stop", "status"]:
|
|
188
|
+
sp = sp_stop if args.command == "stop" else sp_status
|
|
189
|
+
if args.meta_file:
|
|
190
|
+
meta_path = args.meta_file
|
|
191
|
+
else:
|
|
192
|
+
if args.name:
|
|
193
|
+
name = args.name
|
|
194
|
+
else:
|
|
195
|
+
try:
|
|
196
|
+
name, _ = get_task_config(args.name)
|
|
197
|
+
except Exception as e:
|
|
198
|
+
sp.error(str(e))
|
|
199
|
+
meta_path = META_PATH_TEMPLATE.format(name=name)
|
|
200
|
+
if args.command == "stop":
|
|
201
|
+
sys.exit(stop(meta_path))
|
|
202
|
+
else:
|
|
203
|
+
sys.exit(status(meta_path))
|
|
204
|
+
elif args.command == "list":
|
|
205
|
+
dir = args.dir or DEFAULT_META_DIR
|
|
206
|
+
sys.exit(list_processes(dir, args.full))
|
|
207
|
+
elif args.command == "run":
|
|
208
|
+
if not args.name:
|
|
209
|
+
sp_run.error("Please provide a non-empty name for the task.")
|
|
210
|
+
elif check_name_in_config(args.name):
|
|
211
|
+
sp_run.error(
|
|
212
|
+
f"Name '{args.name}' already exists in config. Please choose another name."
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
task_cfg = DmonTaskConfig(
|
|
216
|
+
name=args.name,
|
|
217
|
+
cmd=shlex.join(args.command_list) if args.shell else args.command_list,
|
|
218
|
+
cwd=args.cwd,
|
|
219
|
+
meta_path=args.meta_file or META_PATH_TEMPLATE.format(name=args.name),
|
|
220
|
+
log_path=args.log_file or LOG_PATH_TEMPLATE.format(name=args.name),
|
|
221
|
+
log_rotate=args.log_rotate,
|
|
222
|
+
rotate_log_path=args.rotate_log_path
|
|
223
|
+
or ROTATE_LOG_PATH_TEMPLATE.format(name=args.name),
|
|
224
|
+
)
|
|
225
|
+
sys.exit(start(task_cfg))
|
|
226
|
+
else:
|
|
227
|
+
parser.print_help()
|
|
228
|
+
sys.exit(1)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
if __name__ == "__main__":
|
|
232
|
+
main()
|