python-dmon 0.2.4__py3-none-any.whl → 0.3.0__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.
- dmon/cli.py +83 -36
- dmon/config.py +36 -18
- dmon/control.py +66 -29
- {python_dmon-0.2.4.dist-info → python_dmon-0.3.0.dist-info}/METADATA +17 -1
- {python_dmon-0.2.4.dist-info → python_dmon-0.3.0.dist-info}/RECORD +7 -7
- {python_dmon-0.2.4.dist-info → python_dmon-0.3.0.dist-info}/WHEEL +0 -0
- {python_dmon-0.2.4.dist-info → python_dmon-0.3.0.dist-info}/entry_points.txt +0 -0
dmon/cli.py
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
import shlex
|
|
3
4
|
import sys
|
|
4
5
|
|
|
5
6
|
from colorama import just_fix_windows_console
|
|
6
7
|
|
|
7
8
|
from .config import check_name_in_config, get_task_config
|
|
8
|
-
from .control import
|
|
9
|
+
from .control import (
|
|
10
|
+
execute,
|
|
11
|
+
get_meta_paths,
|
|
12
|
+
list_processes,
|
|
13
|
+
restart,
|
|
14
|
+
start,
|
|
15
|
+
stop,
|
|
16
|
+
status,
|
|
17
|
+
)
|
|
9
18
|
from .constants import (
|
|
10
19
|
DEFAULT_META_DIR,
|
|
11
20
|
DEFAULT_RUN_NAME,
|
|
@@ -50,7 +59,7 @@ def main():
|
|
|
50
59
|
sp_start.add_argument(
|
|
51
60
|
"task",
|
|
52
61
|
help="Configured task name (default: the only task if there's just one)",
|
|
53
|
-
nargs="
|
|
62
|
+
nargs="*",
|
|
54
63
|
)
|
|
55
64
|
sp_start.add_argument(
|
|
56
65
|
"--meta-file",
|
|
@@ -60,20 +69,26 @@ def main():
|
|
|
60
69
|
"--log-file",
|
|
61
70
|
help=f"Path to log file (default: task configured or {LOG_PATH_TEMPLATE})",
|
|
62
71
|
)
|
|
72
|
+
sp_start.add_argument("--all", action="store_true", help="Start all processes")
|
|
63
73
|
|
|
64
74
|
# stop subcommand
|
|
65
75
|
sp_stop = subparsers.add_parser(
|
|
66
76
|
"stop",
|
|
67
|
-
help="Stop
|
|
68
|
-
description="Stop
|
|
77
|
+
help="Stop background process(es)",
|
|
78
|
+
description="Stop background process(es) given name or meta file",
|
|
69
79
|
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
70
80
|
)
|
|
71
81
|
sp_stop.add_argument(
|
|
72
82
|
"task",
|
|
73
83
|
help="Configured task name (default: the only task if there's just one)",
|
|
74
|
-
nargs="
|
|
84
|
+
nargs="*",
|
|
75
85
|
)
|
|
76
86
|
sp_stop.add_argument("--meta-file", help="Path to meta file")
|
|
87
|
+
sp_stop.add_argument(
|
|
88
|
+
"--all",
|
|
89
|
+
action="store_true",
|
|
90
|
+
help=f"Stop all processes in meta dir ({DEFAULT_META_DIR})",
|
|
91
|
+
)
|
|
77
92
|
|
|
78
93
|
# restart subcommand
|
|
79
94
|
sp_restart = subparsers.add_parser(
|
|
@@ -85,7 +100,7 @@ def main():
|
|
|
85
100
|
sp_restart.add_argument(
|
|
86
101
|
"task",
|
|
87
102
|
help="Configured task name (default: the only task if there's just one)",
|
|
88
|
-
nargs="
|
|
103
|
+
nargs="*",
|
|
89
104
|
)
|
|
90
105
|
sp_restart.add_argument(
|
|
91
106
|
"--meta-file",
|
|
@@ -95,23 +110,30 @@ def main():
|
|
|
95
110
|
"--log-file",
|
|
96
111
|
help=f"Path to log file (default: task configured or {LOG_PATH_TEMPLATE})",
|
|
97
112
|
)
|
|
113
|
+
sp_restart.add_argument("--all", action="store_true", help="Restart all processes")
|
|
98
114
|
|
|
99
115
|
# status subcommand
|
|
100
116
|
sp_status = subparsers.add_parser(
|
|
101
117
|
"status",
|
|
102
|
-
help="Check process
|
|
103
|
-
description="Check status of
|
|
118
|
+
help="Check status of background process(es)",
|
|
119
|
+
description="Check status of background process(es) given name or meta file",
|
|
104
120
|
# formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
105
121
|
)
|
|
106
122
|
sp_status.add_argument(
|
|
107
123
|
"task",
|
|
108
124
|
help="Configured task name (default: the only task if there's just one)",
|
|
109
|
-
nargs="
|
|
125
|
+
nargs="*",
|
|
110
126
|
)
|
|
111
127
|
sp_status.add_argument(
|
|
112
128
|
"--meta-file",
|
|
113
129
|
help=f"Path to meta file (default: {META_PATH_TEMPLATE})",
|
|
114
130
|
)
|
|
131
|
+
sp_status.add_argument(
|
|
132
|
+
"-a",
|
|
133
|
+
"--all",
|
|
134
|
+
action="store_true",
|
|
135
|
+
help=f"Check status of all processes in meta dir ({DEFAULT_META_DIR})",
|
|
136
|
+
)
|
|
115
137
|
|
|
116
138
|
# list subcommand
|
|
117
139
|
sp_list = subparsers.add_parser(
|
|
@@ -199,46 +221,71 @@ def main():
|
|
|
199
221
|
if args.command in ["start", "restart"]:
|
|
200
222
|
sp = sp_start if args.command == "start" else sp_restart
|
|
201
223
|
try:
|
|
202
|
-
|
|
224
|
+
tasks, task_cfgs = get_task_config(args.task, args.config, args.all)
|
|
203
225
|
except Exception as e:
|
|
204
226
|
sp.error(str(e))
|
|
205
227
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
228
|
+
# check if meta_file or log_file path is provided;
|
|
229
|
+
# if so, only one task should be specified
|
|
230
|
+
if args.meta_file or args.log_file:
|
|
231
|
+
if len(tasks) == 1:
|
|
232
|
+
task_cfgs[0].meta_path = args.meta_file or task_cfgs[0].meta_path
|
|
233
|
+
task_cfgs[0].log_path = args.log_file or task_cfgs[0].log_path
|
|
234
|
+
else:
|
|
235
|
+
sp.error(
|
|
236
|
+
f"'--meta-file' and '--log-file' can only be specified when {args.command}ing a single task"
|
|
237
|
+
)
|
|
238
|
+
# fill in default values if not provided
|
|
239
|
+
for task, task_cfg in zip(tasks, task_cfgs):
|
|
240
|
+
task_cfg.meta_path = task_cfg.meta_path or META_PATH_TEMPLATE.format(
|
|
241
|
+
task=task
|
|
242
|
+
)
|
|
243
|
+
task_cfg.log_path = task_cfg.log_path or LOG_PATH_TEMPLATE.format(task=task)
|
|
244
|
+
task_cfg.rotate_log_path = (
|
|
245
|
+
task_cfg.rotate_log_path or ROTATE_LOG_PATH_TEMPLATE.format(task=task)
|
|
246
|
+
)
|
|
215
247
|
if args.command == "start":
|
|
216
|
-
sys.exit(start(
|
|
248
|
+
sys.exit(start(task_cfgs))
|
|
217
249
|
else:
|
|
218
|
-
sys.exit(restart(
|
|
250
|
+
sys.exit(restart(task_cfgs))
|
|
219
251
|
elif args.command == "exec":
|
|
220
252
|
try:
|
|
221
|
-
|
|
253
|
+
_, task_cfgs = get_task_config(args.task, args.config)
|
|
222
254
|
except Exception as e:
|
|
223
255
|
sp_exec.error(str(e))
|
|
224
|
-
sys.exit(execute(
|
|
256
|
+
sys.exit(execute(task_cfgs[0]))
|
|
225
257
|
elif args.command in ["stop", "status"]:
|
|
226
258
|
sp = sp_stop if args.command == "stop" else sp_status
|
|
259
|
+
meta_paths = []
|
|
260
|
+
|
|
261
|
+
# Collect meta paths from --all
|
|
262
|
+
if args.all:
|
|
263
|
+
meta_paths.extend(get_meta_paths(DEFAULT_META_DIR))
|
|
264
|
+
|
|
265
|
+
# Collect meta paths from --meta-file
|
|
227
266
|
if args.meta_file:
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
267
|
+
meta_paths.append(args.meta_file)
|
|
268
|
+
|
|
269
|
+
# Collect meta paths from task names
|
|
270
|
+
if len(args.task) > 0:
|
|
271
|
+
tasks = args.task
|
|
272
|
+
meta_paths.extend([META_PATH_TEMPLATE.format(task=task) for task in tasks])
|
|
273
|
+
|
|
274
|
+
# If no meta paths collected, use default task
|
|
275
|
+
if len(meta_paths) == 0:
|
|
276
|
+
try:
|
|
277
|
+
tasks, _ = get_task_config(args.task, args.config)
|
|
278
|
+
except Exception as e:
|
|
279
|
+
sp.error(str(e))
|
|
280
|
+
meta_paths.extend([META_PATH_TEMPLATE.format(task=task) for task in tasks])
|
|
281
|
+
|
|
282
|
+
# Remove duplicates
|
|
283
|
+
unique_meta_paths = sorted(set(Path(p).resolve() for p in meta_paths))
|
|
284
|
+
|
|
238
285
|
if args.command == "stop":
|
|
239
|
-
sys.exit(stop(
|
|
286
|
+
sys.exit(stop(unique_meta_paths))
|
|
240
287
|
else:
|
|
241
|
-
sys.exit(status(
|
|
288
|
+
sys.exit(status(unique_meta_paths))
|
|
242
289
|
elif args.command == "list":
|
|
243
290
|
dir = args.dir or DEFAULT_META_DIR
|
|
244
291
|
sys.exit(list_processes(dir, args.full))
|
|
@@ -260,7 +307,7 @@ def main():
|
|
|
260
307
|
rotate_log_path=args.rotate_log_path
|
|
261
308
|
or ROTATE_LOG_PATH_TEMPLATE.format(task=args.name),
|
|
262
309
|
)
|
|
263
|
-
sys.exit(start(task_cfg))
|
|
310
|
+
sys.exit(start([task_cfg]))
|
|
264
311
|
else:
|
|
265
312
|
parser.print_help()
|
|
266
313
|
sys.exit(1)
|
dmon/config.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Dict, Optional, cast
|
|
3
|
+
from typing import Dict, List, Optional, Sequence, Tuple, Union, cast
|
|
4
4
|
|
|
5
5
|
if sys.version_info >= (3, 11):
|
|
6
6
|
import tomllib
|
|
@@ -121,7 +121,10 @@ def validate_task(task, name: str) -> DmonTaskConfig:
|
|
|
121
121
|
ret.log_rotate = task["log_rotate"]
|
|
122
122
|
|
|
123
123
|
if "log_max_size" in task:
|
|
124
|
-
if
|
|
124
|
+
if (
|
|
125
|
+
not isinstance(task["log_max_size"], (int, float))
|
|
126
|
+
or task["log_max_size"] <= 0
|
|
127
|
+
):
|
|
125
128
|
raise TypeError(
|
|
126
129
|
f"Task '{name}' 'log_max_size' field must be a positive number"
|
|
127
130
|
)
|
|
@@ -155,11 +158,14 @@ def validate_task(task, name: str) -> DmonTaskConfig:
|
|
|
155
158
|
return ret
|
|
156
159
|
|
|
157
160
|
|
|
158
|
-
def get_task_config(
|
|
161
|
+
def get_task_config(
|
|
162
|
+
names: Union[Sequence[str], str, None], cfg_path: Optional[str], all: bool = False
|
|
163
|
+
) -> Tuple[Sequence[str], List[DmonTaskConfig]]:
|
|
159
164
|
"""
|
|
160
|
-
Get the validated task
|
|
161
|
-
If
|
|
162
|
-
If
|
|
165
|
+
Get the validated task configurations for the given task names.
|
|
166
|
+
If 'all' is True, return all tasks.
|
|
167
|
+
If no name specified, and there is only one task, return that task; otherwise, raise ValueError.
|
|
168
|
+
If any task is not found, or required fields are missing, raise TypeError or ValueError.
|
|
163
169
|
|
|
164
170
|
The config is loaded from the given path, or searched for dmon.yaml or pyproject.toml.
|
|
165
171
|
"""
|
|
@@ -169,23 +175,35 @@ def get_task_config(name: Optional[str], cfg_path: Optional[str]):
|
|
|
169
175
|
if not isinstance(tasks, dict):
|
|
170
176
|
raise TypeError("'tasks' must be a table")
|
|
171
177
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
if all:
|
|
179
|
+
names = list(tasks.keys())
|
|
180
|
+
elif isinstance(names, str):
|
|
181
|
+
names = [names]
|
|
182
|
+
elif names is None or len(names) == 0:
|
|
183
|
+
default_task_name = cfg.get("default_task", None)
|
|
184
|
+
if default_task_name:
|
|
185
|
+
if not isinstance(default_task_name, str):
|
|
186
|
+
raise TypeError("'default_task' must be a string")
|
|
187
|
+
names = [default_task_name]
|
|
179
188
|
else:
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
if len(tasks) == 0:
|
|
190
|
+
raise ValueError(f"No task found in {path}")
|
|
191
|
+
elif len(tasks) == 1:
|
|
192
|
+
name = next(iter(tasks))
|
|
193
|
+
assert isinstance(name, str)
|
|
194
|
+
names = [name]
|
|
195
|
+
else:
|
|
196
|
+
raise ValueError(f"Multiple tasks found in {path}; please specify one.")
|
|
197
|
+
|
|
198
|
+
ret_tasks = []
|
|
199
|
+
for name in names:
|
|
182
200
|
name = name.lower()
|
|
183
201
|
if name not in tasks:
|
|
184
202
|
raise ValueError(f"Task '{name}' not found in {path}")
|
|
185
203
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
204
|
+
task = validate_task(tasks[name], name)
|
|
205
|
+
ret_tasks.append(task)
|
|
206
|
+
return names, ret_tasks
|
|
189
207
|
|
|
190
208
|
|
|
191
209
|
def check_name_in_config(name: str) -> bool:
|
dmon/control.py
CHANGED
|
@@ -6,7 +6,7 @@ import signal
|
|
|
6
6
|
import sys
|
|
7
7
|
import subprocess
|
|
8
8
|
import time
|
|
9
|
-
from typing import List
|
|
9
|
+
from typing import List, Sequence
|
|
10
10
|
|
|
11
11
|
import psutil
|
|
12
12
|
from termcolor import colored
|
|
@@ -33,7 +33,17 @@ def ensure_log_dir(log_path: Path):
|
|
|
33
33
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def start(
|
|
36
|
+
def start(cfgs: Sequence[DmonTaskConfig]):
|
|
37
|
+
ret = 0
|
|
38
|
+
for idx, cfg in enumerate(cfgs):
|
|
39
|
+
# non-zero if any start() fails
|
|
40
|
+
ret |= start_single(cfg)
|
|
41
|
+
if idx < len(cfgs) - 1:
|
|
42
|
+
print("---", file=sys.stderr) # print a blank line between tasks
|
|
43
|
+
return ret
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def start_single(cfg: DmonTaskConfig):
|
|
37
47
|
meta_path = Path(cfg.meta_path).resolve()
|
|
38
48
|
log_path = Path(cfg.log_path).resolve()
|
|
39
49
|
cwd = Path(cfg.cwd).resolve()
|
|
@@ -166,7 +176,17 @@ def start(cfg: DmonTaskConfig):
|
|
|
166
176
|
return 0
|
|
167
177
|
|
|
168
178
|
|
|
169
|
-
def stop(
|
|
179
|
+
def stop(meta_paths: Sequence[PathType], timeout=5.0):
|
|
180
|
+
ret = 0
|
|
181
|
+
for idx, meta_path in enumerate(meta_paths):
|
|
182
|
+
# non-zero if any stop() fails
|
|
183
|
+
ret |= stop_single(meta_path=meta_path, timeout=timeout)
|
|
184
|
+
if idx < len(meta_paths) - 1:
|
|
185
|
+
print(file=sys.stderr) # print a blank line between tasks
|
|
186
|
+
return ret
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def stop_single(
|
|
170
190
|
meta_path: PathType,
|
|
171
191
|
timeout=5.0,
|
|
172
192
|
):
|
|
@@ -345,33 +365,41 @@ def terminate_win(proc: psutil.Process, timeout):
|
|
|
345
365
|
|
|
346
366
|
|
|
347
367
|
def restart(
|
|
348
|
-
|
|
368
|
+
cfgs: Sequence[DmonTaskConfig],
|
|
349
369
|
timeout=5.0,
|
|
350
370
|
):
|
|
351
|
-
|
|
371
|
+
meta_paths = [cfg.meta_path for cfg in cfgs]
|
|
372
|
+
stop(meta_paths, timeout=timeout)
|
|
352
373
|
print("--- Restarting ---", file=sys.stderr)
|
|
353
|
-
return start(
|
|
374
|
+
return start(cfgs)
|
|
354
375
|
|
|
355
376
|
|
|
356
|
-
def status(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
377
|
+
def status(meta_paths: Sequence[PathType]):
|
|
378
|
+
ret = 0
|
|
379
|
+
metas = []
|
|
380
|
+
for idx, meta_path in enumerate(meta_paths):
|
|
381
|
+
meta_path = Path(meta_path).resolve()
|
|
382
|
+
meta = DmonMeta.load(meta_path)
|
|
383
|
+
if meta is None:
|
|
384
|
+
print(
|
|
385
|
+
colored(
|
|
386
|
+
"Status failed: meta file not found (maybe not started)\n",
|
|
387
|
+
color="red",
|
|
388
|
+
attrs=["bold"],
|
|
389
|
+
)
|
|
390
|
+
+ str(meta_path),
|
|
391
|
+
file=sys.stderr,
|
|
365
392
|
)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
393
|
+
ret |= 1
|
|
394
|
+
else:
|
|
395
|
+
print_status(meta)
|
|
396
|
+
metas.append(meta)
|
|
397
|
+
if idx < len(meta_paths) - 1:
|
|
398
|
+
print("---", file=sys.stderr)
|
|
399
|
+
if metas:
|
|
400
|
+
print("\nProcess Tree:", file=sys.stderr)
|
|
401
|
+
print_process_table(metas)
|
|
402
|
+
return ret
|
|
375
403
|
|
|
376
404
|
|
|
377
405
|
def check_same_process(proc: psutil.Process, create_time: float) -> bool:
|
|
@@ -523,14 +551,23 @@ def print_process_table(metas: List[DmonMeta], full_width: bool = False):
|
|
|
523
551
|
return processes
|
|
524
552
|
|
|
525
553
|
|
|
526
|
-
def
|
|
554
|
+
def get_meta_paths(dir: PathType) -> List[Path]:
|
|
527
555
|
target_dmon_dir = Path(dir).resolve()
|
|
528
|
-
|
|
556
|
+
meta_paths: List[Path] = []
|
|
529
557
|
if target_dmon_dir.exists() and target_dmon_dir.is_dir():
|
|
530
558
|
for meta_file in target_dmon_dir.glob(f"*{META_SUFFIX}"):
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
559
|
+
meta_paths.append(meta_file)
|
|
560
|
+
return meta_paths
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def list_processes(dir: PathType, full_width: bool):
|
|
564
|
+
target_dmon_dir = Path(dir).resolve()
|
|
565
|
+
meta_paths = get_meta_paths(target_dmon_dir)
|
|
566
|
+
metas = []
|
|
567
|
+
for meta_path in meta_paths:
|
|
568
|
+
meta = DmonMeta.load(meta_path)
|
|
569
|
+
if meta is not None:
|
|
570
|
+
metas.append(meta)
|
|
534
571
|
# sort by name (case-insensitive)
|
|
535
572
|
metas.sort(key=lambda m: m.task.lower())
|
|
536
573
|
n_task = len(metas)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: python-dmon
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A lightweight, cross-platform daemon manager that runs any command as a background process.
|
|
5
5
|
Keywords: python-dmon,dmon,daemon,background,detach,process management
|
|
6
6
|
Author: Atomie CHEN
|
|
@@ -21,6 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
[](https://github.com/atomiechen/python-dmon)
|
|
23
23
|
[](https://pypi.org/project/python-dmon/)
|
|
24
|
+
[](https://deepwiki.com/atomiechen/python-dmon)
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
A lightweight, cross-platform daemon manager that runs any command — called a *task* — as a background process.
|
|
@@ -113,6 +114,9 @@ dmon start app
|
|
|
113
114
|
# Stop a running task
|
|
114
115
|
dmon stop app
|
|
115
116
|
|
|
117
|
+
# Restart a task
|
|
118
|
+
dmon restart app
|
|
119
|
+
|
|
116
120
|
# Check task status
|
|
117
121
|
dmon status app
|
|
118
122
|
|
|
@@ -120,11 +124,23 @@ dmon status app
|
|
|
120
124
|
dmon exec app
|
|
121
125
|
```
|
|
122
126
|
|
|
127
|
+
You can specify multiple tasks at once, e.g.: `dmon start app1 app2 app3`, except for `dmon exec` which only accepts one task.
|
|
128
|
+
|
|
129
|
+
Or use `--all` to operate on all tasks:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
# all configured tasks
|
|
133
|
+
dmon start/stop/restart --all
|
|
134
|
+
# all running tasks
|
|
135
|
+
dmon stop/status --all
|
|
136
|
+
```
|
|
137
|
+
|
|
123
138
|
If you have defined `default_task`, or only one task is defined in the config file, you can omit the task name:
|
|
124
139
|
|
|
125
140
|
```sh
|
|
126
141
|
dmon start
|
|
127
142
|
dmon stop
|
|
143
|
+
dmon restart
|
|
128
144
|
dmon status
|
|
129
145
|
dmon exec
|
|
130
146
|
```
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
dmon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
dmon/__main__.py,sha256=wu5N2wk8mvBgyvr2ghmQf4prezAe0_i-p123VVreyYc,62
|
|
3
|
-
dmon/cli.py,sha256=
|
|
4
|
-
dmon/config.py,sha256=
|
|
3
|
+
dmon/cli.py,sha256=NgTrOsYjXRPI6BO1T9VReO__quyis91sY04nfk7OWTQ,10514
|
|
4
|
+
dmon/config.py,sha256=JAxasW5G0NIok6hZUZVEpsvF3vp5iiDNr2pjnLpUmh4,7911
|
|
5
5
|
dmon/constants.py,sha256=uJPI66IJvT6vhamqEDeqHjZQS12RxCPe3DD5yCU0UR8,407
|
|
6
|
-
dmon/control.py,sha256=
|
|
6
|
+
dmon/control.py,sha256=bjRv2YWSo4RFoUHNl1kU1S_XHjC3tWH0aR9QgQtpDY0,18758
|
|
7
7
|
dmon/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
dmon/runner.py,sha256=zW5dPan0RFAlTsuHwCZ7Pklxt6M740Cu7y8m1f5U9xU,6096
|
|
9
9
|
dmon/types.py,sha256=Cbppb5os7GoKCcwr66S5ge_DunuJepeefpnZGaSr788,1799
|
|
10
10
|
dmon/utils.py,sha256=zVQC9YNhMQu4hrAp9k2ds2egnbWZZv7S5w8i2oVIPJg,808
|
|
11
|
-
python_dmon-0.
|
|
12
|
-
python_dmon-0.
|
|
13
|
-
python_dmon-0.
|
|
14
|
-
python_dmon-0.
|
|
11
|
+
python_dmon-0.3.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
12
|
+
python_dmon-0.3.0.dist-info/entry_points.txt,sha256=1XmEpyjShANXEHMIMa4p3WXpcllIZfGt5DQyTFuSI74,78
|
|
13
|
+
python_dmon-0.3.0.dist-info/METADATA,sha256=KmrhqMP-5A4CVpv1iJS1UDbmMGEpfELMtFLMAs-k8u0,6661
|
|
14
|
+
python_dmon-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|