meerschaum 2.3.0rc1__py3-none-any.whl → 2.3.0rc3__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.
- meerschaum/_internal/arguments/__init__.py +1 -1
- meerschaum/_internal/arguments/_parse_arguments.py +56 -2
- meerschaum/_internal/entry.py +63 -22
- meerschaum/_internal/shell/Shell.py +80 -15
- meerschaum/actions/delete.py +17 -7
- meerschaum/actions/start.py +2 -6
- meerschaum/api/dash/callbacks/jobs.py +36 -44
- meerschaum/api/dash/jobs.py +24 -15
- meerschaum/api/routes/_actions.py +6 -5
- meerschaum/api/routes/_jobs.py +19 -1
- meerschaum/config/_jobs.py +1 -1
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +2 -0
- meerschaum/connectors/api/APIConnector.py +1 -0
- meerschaum/connectors/api/_jobs.py +13 -2
- meerschaum/connectors/parse.py +0 -1
- meerschaum/jobs/_Job.py +24 -7
- meerschaum/jobs/_SystemdExecutor.py +118 -49
- meerschaum/jobs/__init__.py +41 -12
- meerschaum/utils/daemon/Daemon.py +14 -0
- meerschaum/utils/daemon/_names.py +1 -1
- meerschaum/utils/formatting/_jobs.py +2 -14
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/METADATA +1 -1
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/RECORD +30 -30
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/LICENSE +0 -0
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/NOTICE +0 -0
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/WHEEL +0 -0
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/top_level.txt +0 -0
- {meerschaum-2.3.0rc1.dist-info → meerschaum-2.3.0rc3.dist-info}/zip-safe +0 -0
@@ -8,7 +8,7 @@ This package includes argument parsing utilities.
|
|
8
8
|
|
9
9
|
from meerschaum._internal.arguments._parse_arguments import (
|
10
10
|
parse_arguments, parse_line, remove_leading_action,
|
11
|
-
parse_dict_to_sysargs,
|
11
|
+
parse_dict_to_sysargs, split_chained_sysargs,
|
12
12
|
)
|
13
13
|
from meerschaum._internal.arguments._parser import parser
|
14
14
|
from meerschaum.plugins import add_plugin_argument
|
@@ -19,6 +19,44 @@ _locks = {
|
|
19
19
|
_loaded_plugins_args: bool = False
|
20
20
|
|
21
21
|
|
22
|
+
def split_chained_sysargs(sysargs: List[str]) -> List[List[str]]:
|
23
|
+
"""
|
24
|
+
Split a `sysargs` list containing "and" keys (`&&`)
|
25
|
+
into a list of individual `sysargs`.
|
26
|
+
"""
|
27
|
+
from meerschaum.config.static import STATIC_CONFIG
|
28
|
+
and_key = STATIC_CONFIG['system']['arguments']['and_key']
|
29
|
+
|
30
|
+
if not sysargs or and_key not in sysargs:
|
31
|
+
return [sysargs]
|
32
|
+
|
33
|
+
### Coalesce and consecutive joiners into one.
|
34
|
+
coalesce_args = []
|
35
|
+
previous_arg = None
|
36
|
+
for arg in [_arg for _arg in sysargs]:
|
37
|
+
if arg == and_key and previous_arg == and_key:
|
38
|
+
continue
|
39
|
+
coalesce_args.append(arg)
|
40
|
+
previous_arg = arg
|
41
|
+
|
42
|
+
### Remove any joiners from the ends.
|
43
|
+
if coalesce_args[0] == and_key:
|
44
|
+
coalesce_args = coalesce_args[1:]
|
45
|
+
if coalesce_args[-1] == and_key:
|
46
|
+
coalesce_args = coalesce_args[:-1]
|
47
|
+
|
48
|
+
chained_sysargs = []
|
49
|
+
current_sysargs = []
|
50
|
+
for arg in coalesce_args:
|
51
|
+
if arg != and_key:
|
52
|
+
current_sysargs.append(arg)
|
53
|
+
else:
|
54
|
+
chained_sysargs.append(current_sysargs)
|
55
|
+
current_sysargs = []
|
56
|
+
chained_sysargs.append(current_sysargs)
|
57
|
+
return chained_sysargs
|
58
|
+
|
59
|
+
|
22
60
|
def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
|
23
61
|
"""
|
24
62
|
Parse a list of arguments into standard Meerschaum arguments.
|
@@ -206,9 +244,24 @@ def parse_dict_to_sysargs(
|
|
206
244
|
args_dict: Dict[str, Any]
|
207
245
|
) -> List[str]:
|
208
246
|
"""Revert an arguments dictionary back to a command line list."""
|
247
|
+
import shlex
|
209
248
|
from meerschaum._internal.arguments._parser import get_arguments_triggers
|
210
|
-
|
211
|
-
|
249
|
+
from meerschaum.config.static import STATIC_CONFIG
|
250
|
+
from meerschaum.utils.warnings import warn
|
251
|
+
|
252
|
+
and_key = STATIC_CONFIG['system']['arguments']['and_key']
|
253
|
+
if (line := args_dict.get('line', None)):
|
254
|
+
return shlex.split(line)
|
255
|
+
|
256
|
+
if (_sysargs := args_dict.get('sysargs', None)):
|
257
|
+
return _sysargs
|
258
|
+
|
259
|
+
action = args_dict.get('action', None)
|
260
|
+
if action and and_key in action:
|
261
|
+
warn(f"Cannot determine flags from chained actions:\n{args_dict}")
|
262
|
+
|
263
|
+
sysargs: List[str] = []
|
264
|
+
sysargs.extend(action or [])
|
212
265
|
allow_none_args = {'location_keys'}
|
213
266
|
|
214
267
|
triggers = get_arguments_triggers()
|
@@ -216,6 +269,7 @@ def parse_dict_to_sysargs(
|
|
216
269
|
for a, t in triggers.items():
|
217
270
|
if a == 'action' or a not in args_dict:
|
218
271
|
continue
|
272
|
+
|
219
273
|
### Add boolean flags
|
220
274
|
if isinstance(args_dict[a], bool):
|
221
275
|
if args_dict[a] is True:
|
meerschaum/_internal/entry.py
CHANGED
@@ -40,31 +40,68 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
|
40
40
|
-------
|
41
41
|
A `SuccessTuple` indicating success.
|
42
42
|
"""
|
43
|
-
|
43
|
+
import shlex
|
44
|
+
from meerschaum.utils.formatting import make_header
|
45
|
+
from meerschaum._internal.arguments import parse_arguments, split_chained_sysargs
|
44
46
|
from meerschaum.config.static import STATIC_CONFIG
|
45
47
|
if sysargs is None:
|
46
48
|
sysargs = []
|
47
49
|
if not isinstance(sysargs, list):
|
48
|
-
import shlex
|
49
50
|
sysargs = shlex.split(sysargs)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
|
52
|
+
has_daemon = '-d' in sysargs or '--daemon' in sysargs
|
53
|
+
has_start_job = sysargs[:2] == ['start', 'job']
|
54
|
+
chained_sysargs = (
|
55
|
+
[sysargs]
|
56
|
+
if has_daemon or has_start_job
|
57
|
+
else split_chained_sysargs(sysargs)
|
54
58
|
)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
results: List[SuccessTuple] = []
|
60
|
+
|
61
|
+
for _sysargs in chained_sysargs:
|
62
|
+
args = parse_arguments(_sysargs)
|
63
|
+
argparse_exception = args.get(
|
64
|
+
STATIC_CONFIG['system']['arguments']['failure_key'],
|
65
|
+
None,
|
66
|
+
)
|
67
|
+
if argparse_exception is not None:
|
68
|
+
args_text = args.get('text', '')
|
69
|
+
if not args_text.startswith('show arguments'):
|
70
|
+
return (
|
71
|
+
False,
|
72
|
+
(
|
73
|
+
"Invalid arguments:"
|
74
|
+
+ (f"\n{args_text}" if args_text else '')
|
75
|
+
+ f"\n {argparse_exception}"
|
76
|
+
)
|
77
|
+
)
|
78
|
+
|
79
|
+
entry_success, entry_msg = entry_with_args(**args)
|
80
|
+
if not entry_success:
|
81
|
+
return entry_success, entry_msg
|
82
|
+
|
83
|
+
results.append((entry_success, entry_msg))
|
84
|
+
|
85
|
+
success = all(_success for _success, _ in results)
|
86
|
+
msg = (
|
87
|
+
results[0][1]
|
88
|
+
if len(results) == 1
|
89
|
+
else 'Successfully completed steps:\n\n' + '\n'.join(
|
90
|
+
[
|
60
91
|
(
|
61
|
-
|
62
|
-
+
|
63
|
-
+ f"\n {argparse_exception}"
|
92
|
+
make_header(shlex.join(_sysargs))
|
93
|
+
+ '\n ' + _msg + '\n'
|
64
94
|
)
|
65
|
-
|
95
|
+
for i, ((_, _msg), _sysargs) in enumerate(zip(results, chained_sysargs))
|
96
|
+
]
|
97
|
+
)
|
98
|
+
)
|
99
|
+
if _systemd_result_path:
|
100
|
+
import json
|
101
|
+
with open(_systemd_result_path, 'w+', encoding='utf-8') as f:
|
102
|
+
json.dump((success, msg), f)
|
66
103
|
|
67
|
-
return
|
104
|
+
return success, msg
|
68
105
|
|
69
106
|
|
70
107
|
def entry_with_args(
|
@@ -79,7 +116,16 @@ def entry_with_args(
|
|
79
116
|
import inspect
|
80
117
|
from meerschaum.actions import get_action, get_main_action_name
|
81
118
|
from meerschaum._internal.arguments import remove_leading_action
|
82
|
-
from meerschaum.utils.venv import
|
119
|
+
from meerschaum.utils.venv import active_venvs, deactivate_venv
|
120
|
+
from meerschaum.config.static import STATIC_CONFIG
|
121
|
+
|
122
|
+
and_key = STATIC_CONFIG['system']['arguments']['and_key']
|
123
|
+
escaped_and_key = STATIC_CONFIG['system']['arguments']['escaped_and_key']
|
124
|
+
if and_key in (sysargs := kw.get('sysargs', [])):
|
125
|
+
if '-d' in sysargs or '--daemon' in sysargs:
|
126
|
+
sysargs = [(arg if arg != and_key else escaped_and_key) for arg in sysargs]
|
127
|
+
return entry(sysargs)
|
128
|
+
|
83
129
|
if kw.get('trace', None):
|
84
130
|
from meerschaum.utils.misc import debug_trace
|
85
131
|
debug_trace()
|
@@ -159,11 +205,6 @@ def entry_with_args(
|
|
159
205
|
for venv in [venv for venv in active_venvs]:
|
160
206
|
deactivate_venv(venv, debug=kw.get('debug', False), force=True)
|
161
207
|
|
162
|
-
if _systemd_result_path:
|
163
|
-
import json
|
164
|
-
with open(_systemd_result_path, 'w+', encoding='utf-8') as f:
|
165
|
-
json.dump(result, f)
|
166
|
-
|
167
208
|
return result
|
168
209
|
|
169
210
|
|
@@ -8,6 +8,8 @@ This module is the entry point for the interactive shell.
|
|
8
8
|
from __future__ import annotations
|
9
9
|
import os
|
10
10
|
from copy import deepcopy
|
11
|
+
from itertools import chain
|
12
|
+
|
11
13
|
from meerschaum.utils.typing import Union, SuccessTuple, Any, Callable, Optional, List, Dict
|
12
14
|
from meerschaum.utils.packages import attempt_import
|
13
15
|
from meerschaum.config import __doc__, __version__ as version, get_config
|
@@ -30,6 +32,12 @@ from meerschaum._internal.shell.ShellCompleter import ShellCompleter
|
|
30
32
|
_clear_screen = get_config('shell', 'clear_screen', patch=True)
|
31
33
|
from meerschaum.utils.misc import string_width, remove_ansi
|
32
34
|
from meerschaum.jobs import get_executor_keys_from_context
|
35
|
+
from meerschaum.config.static import STATIC_CONFIG
|
36
|
+
from meerschaum._internal.arguments._parse_arguments import (
|
37
|
+
split_chained_sysargs,
|
38
|
+
parse_arguments,
|
39
|
+
parse_line,
|
40
|
+
)
|
33
41
|
|
34
42
|
patch = True
|
35
43
|
### remove default cmd2 commands
|
@@ -63,6 +71,8 @@ reserved_completers = {
|
|
63
71
|
### To handle dynamic reloading, store shell attributes externally.
|
64
72
|
### This is because the shell object address gets lost upon reloads.
|
65
73
|
shell_attrs = {}
|
74
|
+
AND_KEY: str = STATIC_CONFIG['system']['arguments']['and_key']
|
75
|
+
ESCAPED_AND_KEY: str = STATIC_CONFIG['system']['arguments']['escaped_and_key']
|
66
76
|
|
67
77
|
def _insert_shell_actions(
|
68
78
|
_shell: Optional['Shell'] = None,
|
@@ -111,7 +121,6 @@ def _completer_wrapper(
|
|
111
121
|
if _check_keys is not None:
|
112
122
|
return _check_keys
|
113
123
|
|
114
|
-
from meerschaum._internal.arguments._parse_arguments import parse_line
|
115
124
|
args = parse_line(line)
|
116
125
|
if target.__name__ != 'default_action_completer':
|
117
126
|
if len(args['action']) > 0:
|
@@ -149,7 +158,6 @@ def default_action_completer(
|
|
149
158
|
|
150
159
|
def _check_complete_keys(line: str) -> Optional[List[str]]:
|
151
160
|
from meerschaum._internal.arguments._parser import parser, get_arguments_triggers
|
152
|
-
from meerschaum._internal.arguments._parse_arguments import parse_line
|
153
161
|
|
154
162
|
### TODO Add all triggers
|
155
163
|
trigger_args = {
|
@@ -546,16 +554,68 @@ class Shell(cmd.Cmd):
|
|
546
554
|
else:
|
547
555
|
main_action_name = args['action'][0]
|
548
556
|
|
557
|
+
def _add_flag_to_sysargs(
|
558
|
+
chained_sysargs, key, value, flag, shell_key=None,
|
559
|
+
):
|
560
|
+
shell_key = shell_key or key
|
561
|
+
shell_value = remove_ansi(shell_attrs.get(shell_key) or '')
|
562
|
+
if key == 'mrsm_instance':
|
563
|
+
default_value = get_config('meerschaum', 'instance')
|
564
|
+
elif key == 'repository':
|
565
|
+
default_value = get_config('meerschaum', 'default_repository')
|
566
|
+
elif key == 'executor_keys':
|
567
|
+
default_value = get_executor_keys_from_context()
|
568
|
+
else:
|
569
|
+
default_value = None
|
570
|
+
|
571
|
+
if shell_value == default_value:
|
572
|
+
return
|
573
|
+
|
574
|
+
for sysargs in chained_sysargs:
|
575
|
+
kwargs = parse_arguments(sysargs)
|
576
|
+
if key in kwargs:
|
577
|
+
continue
|
578
|
+
sysargs.extend([flag, value])
|
579
|
+
|
580
|
+
args['sysargs'] = list(
|
581
|
+
chain.from_iterable(
|
582
|
+
sub_sysargs + [AND_KEY]
|
583
|
+
for sub_sysargs in chained_sysargs
|
584
|
+
)
|
585
|
+
)[:-1]
|
586
|
+
|
587
|
+
|
549
588
|
### if no instance is provided, use current shell default,
|
550
589
|
### but not for the 'api' command (to avoid recursion)
|
551
|
-
if
|
552
|
-
|
590
|
+
if main_action_name != 'api':
|
591
|
+
chained_sysargs = split_chained_sysargs(args['sysargs'])
|
592
|
+
chained_filtered_sysargs = split_chained_sysargs(args['filtered_sysargs'])
|
593
|
+
mrsm_instance = shell_attrs['instance_keys']
|
594
|
+
args['mrsm_instance'] = mrsm_instance
|
595
|
+
_add_flag_to_sysargs(
|
596
|
+
chained_sysargs, 'mrsm_instance', mrsm_instance, '-i', 'instance_keys',
|
597
|
+
)
|
598
|
+
_add_flag_to_sysargs(
|
599
|
+
chained_filtered_sysargs, 'mrsm_instance', mrsm_instance, '-i', 'instance_keys',
|
600
|
+
)
|
553
601
|
|
554
|
-
|
555
|
-
args['repository'] =
|
602
|
+
repo_keys = str(shell_attrs['repo_keys'])
|
603
|
+
args['repository'] = repo_keys
|
604
|
+
_add_flag_to_sysargs(
|
605
|
+
chained_sysargs, 'repository', repo_keys, '-r', 'repo_keys',
|
606
|
+
)
|
607
|
+
_add_flag_to_sysargs(
|
608
|
+
chained_filtered_sysargs, 'repository', repo_keys, '-r', 'repo_keys',
|
609
|
+
)
|
556
610
|
|
557
|
-
|
558
|
-
args['executor_keys'] = remove_ansi(
|
611
|
+
executor_keys = remove_ansi(str(shell_attrs['executor_keys']))
|
612
|
+
args['executor_keys'] = remove_ansi(executor_keys)
|
613
|
+
_add_flag_to_sysargs(
|
614
|
+
chained_sysargs, 'executor_keys', executor_keys, '-e',
|
615
|
+
)
|
616
|
+
_add_flag_to_sysargs(
|
617
|
+
chained_filtered_sysargs, 'executor_keys', executor_keys, '-e',
|
618
|
+
)
|
559
619
|
|
560
620
|
### parse out empty strings
|
561
621
|
if args['action'][0].strip("\"'") == '':
|
@@ -630,12 +690,12 @@ class Shell(cmd.Cmd):
|
|
630
690
|
info(f"Debug mode is {'on' if shell_attrs['debug'] else 'off'}.")
|
631
691
|
|
632
692
|
def do_instance(
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
693
|
+
self,
|
694
|
+
action: Optional[List[str]] = None,
|
695
|
+
executor_keys=None,
|
696
|
+
debug: bool = False,
|
697
|
+
**kw: Any
|
698
|
+
) -> SuccessTuple:
|
639
699
|
"""
|
640
700
|
Temporarily set a default Meerschaum instance for the duration of the shell.
|
641
701
|
The default instance is loaded from the Meerschaum configuraton file
|
@@ -804,6 +864,7 @@ class Shell(cmd.Cmd):
|
|
804
864
|
from meerschaum import get_connector
|
805
865
|
from meerschaum.connectors.parse import parse_executor_keys
|
806
866
|
from meerschaum.utils.warnings import warn, info
|
867
|
+
from meerschaum.jobs import get_executor_keys_from_context
|
807
868
|
|
808
869
|
if action is None:
|
809
870
|
action = []
|
@@ -814,6 +875,10 @@ class Shell(cmd.Cmd):
|
|
814
875
|
executor_keys = ''
|
815
876
|
if executor_keys == '':
|
816
877
|
executor_keys = get_executor_keys_from_context()
|
878
|
+
|
879
|
+
if executor_keys == 'systemd' and get_executor_keys_from_context() != 'systemd':
|
880
|
+
warn(f"Cannot execute via `systemd`, falling back to `local`...", stack=False)
|
881
|
+
executor_keys = 'local'
|
817
882
|
|
818
883
|
conn = parse_executor_keys(executor_keys, debug=debug)
|
819
884
|
|
@@ -987,7 +1052,7 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
|
|
987
1052
|
)
|
988
1053
|
|
989
1054
|
try:
|
990
|
-
typ, label = shell_attrs['instance_keys'].split(':')
|
1055
|
+
typ, label = shell_attrs['instance_keys'].split(':', maxsplit=1)
|
991
1056
|
connected = typ in connectors and label in connectors[typ]
|
992
1057
|
except Exception as e:
|
993
1058
|
connected = False
|
meerschaum/actions/delete.py
CHANGED
@@ -509,12 +509,22 @@ def _complete_delete_jobs(
|
|
509
509
|
get_stopped_jobs,
|
510
510
|
get_paused_jobs,
|
511
511
|
get_running_jobs,
|
512
|
+
get_executor_keys_from_context,
|
512
513
|
)
|
513
514
|
from meerschaum.utils.misc import remove_ansi
|
515
|
+
from meerschaum.connectors.parse import parse_executor_keys
|
514
516
|
|
515
|
-
executor_keys =
|
517
|
+
executor_keys = (
|
518
|
+
executor_keys
|
519
|
+
or remove_ansi(
|
520
|
+
shell_attrs.get('executor_keys', get_executor_keys_from_context())
|
521
|
+
)
|
522
|
+
)
|
523
|
+
|
524
|
+
if parse_executor_keys(executor_keys, construct=False) is None:
|
525
|
+
return []
|
516
526
|
|
517
|
-
jobs = get_jobs(executor_keys)
|
527
|
+
jobs = get_jobs(executor_keys, include_hidden=False)
|
518
528
|
if _get_job_method:
|
519
529
|
method_keys = [_get_job_method] if isinstance(_get_job_method, str) else _get_job_method
|
520
530
|
method_jobs = {}
|
@@ -540,11 +550,11 @@ def _complete_delete_jobs(
|
|
540
550
|
|
541
551
|
|
542
552
|
def _delete_venvs(
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
553
|
+
action: Optional[List[str]] = None,
|
554
|
+
yes: bool = False,
|
555
|
+
force: bool = False,
|
556
|
+
**kwargs: Any
|
557
|
+
) -> SuccessTuple:
|
548
558
|
"""
|
549
559
|
Remove virtual environments.
|
550
560
|
Specify which venvs to remove, or remove everything at once.
|
meerschaum/actions/start.py
CHANGED
@@ -82,6 +82,7 @@ def _start_api(action: Optional[List[str]] = None, **kw):
|
|
82
82
|
from meerschaum.actions import actions
|
83
83
|
return actions['api'](action=['start'], **kw)
|
84
84
|
|
85
|
+
|
85
86
|
def _start_jobs(
|
86
87
|
action: Optional[List[str]] = None,
|
87
88
|
name: Optional[str] = None,
|
@@ -119,25 +120,20 @@ def _start_jobs(
|
|
119
120
|
Start the job 'happy_seal' but via the `--name` flag.
|
120
121
|
This only applies when no text follows the words 'start job'.
|
121
122
|
"""
|
122
|
-
import textwrap
|
123
123
|
from meerschaum.utils.warnings import warn, info
|
124
124
|
from meerschaum.utils.daemon._names import get_new_daemon_name
|
125
125
|
from meerschaum.jobs import (
|
126
126
|
Job,
|
127
|
-
get_jobs,
|
128
127
|
get_filtered_jobs,
|
129
128
|
get_stopped_jobs,
|
130
129
|
get_running_jobs,
|
131
130
|
get_paused_jobs,
|
132
|
-
get_restart_jobs,
|
133
131
|
_install_healthcheck_job,
|
134
132
|
)
|
135
|
-
from meerschaum._internal.arguments._parse_arguments import parse_arguments
|
136
133
|
from meerschaum.actions import actions
|
137
134
|
from meerschaum.utils.prompt import yes_no
|
138
135
|
from meerschaum.utils.formatting import print_tuple
|
139
|
-
from meerschaum.utils.formatting._jobs import
|
140
|
-
from meerschaum.utils.formatting._shell import clear_screen
|
136
|
+
from meerschaum.utils.formatting._jobs import pprint_jobs
|
141
137
|
from meerschaum.utils.misc import items_str
|
142
138
|
|
143
139
|
names = []
|
@@ -24,13 +24,13 @@ from dash import Patch
|
|
24
24
|
html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
|
25
25
|
import dash_bootstrap_components as dbc
|
26
26
|
from meerschaum.api.dash.components import alert_from_success_tuple, build_cards_grid
|
27
|
-
from meerschaum.utils.daemon import Daemon
|
28
27
|
from dash.exceptions import PreventUpdate
|
29
28
|
from meerschaum.api.dash.jobs import (
|
30
29
|
build_manage_job_buttons_div_children,
|
31
30
|
build_status_children,
|
32
31
|
build_process_timestamps_children,
|
33
32
|
)
|
33
|
+
from meerschaum.jobs import Job
|
34
34
|
from meerschaum.api.dash.users import is_session_authenticated
|
35
35
|
|
36
36
|
@dash_app.callback(
|
@@ -53,15 +53,11 @@ def download_job_logs(n_clicks):
|
|
53
53
|
raise PreventUpdate
|
54
54
|
|
55
55
|
component_dict = json.loads(ctx[0]['prop_id'].split('.' + 'n_clicks')[0])
|
56
|
-
|
57
|
-
daemon = Daemon(daemon_id=daemon_id)
|
56
|
+
job_name = component_dict['index']
|
58
57
|
now = datetime.now(timezone.utc)
|
59
|
-
filename = (
|
60
|
-
daemon.rotating_log.file_path.name[:(-1 * len('.log'))]
|
61
|
-
+ '_' + str(int(now.timestamp())) + '.log'
|
62
|
-
)
|
58
|
+
filename = job_name + '_' + str(int(now.timestamp())) + '.log'
|
63
59
|
return {
|
64
|
-
'content':
|
60
|
+
'content': job.get_logs(),
|
65
61
|
'filename': filename,
|
66
62
|
}
|
67
63
|
|
@@ -73,12 +69,14 @@ def download_job_logs(n_clicks):
|
|
73
69
|
Output({'type': 'process-timestamps-div', 'index': MATCH}, 'children'),
|
74
70
|
Input({'type': 'manage-job-button', 'action': ALL, 'index': MATCH}, 'n_clicks'),
|
75
71
|
State('session-store', 'data'),
|
72
|
+
State({'type': 'job-label-p', 'index': MATCH}, 'children'),
|
76
73
|
prevent_initial_call = True,
|
77
74
|
)
|
78
75
|
def manage_job_button_click(
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
n_clicks: Optional[int] = None,
|
77
|
+
session_data: Optional[Dict[str, Any]] = None,
|
78
|
+
job_label: Optional[str] = None,
|
79
|
+
):
|
82
80
|
"""
|
83
81
|
Start, stop, pause, or delete the given job.
|
84
82
|
"""
|
@@ -102,20 +100,20 @@ def manage_job_button_click(
|
|
102
100
|
raise PreventUpdate
|
103
101
|
|
104
102
|
component_dict = json.loads(ctx[0]['prop_id'].split('.' + 'n_clicks')[0])
|
105
|
-
|
103
|
+
job_name = component_dict['index']
|
106
104
|
manage_job_action = component_dict['action']
|
107
105
|
try:
|
108
|
-
|
106
|
+
job = Job(job_name, job_label.replace('\n', ' ') if job_label else None)
|
109
107
|
except Exception as e:
|
110
|
-
|
111
|
-
if
|
108
|
+
job = None
|
109
|
+
if job is None:
|
112
110
|
raise PreventUpdate
|
113
111
|
|
114
112
|
manage_functions = {
|
115
|
-
'start':
|
116
|
-
'stop':
|
117
|
-
'pause':
|
118
|
-
'delete':
|
113
|
+
'start': job.start,
|
114
|
+
'stop': job.stop,
|
115
|
+
'pause': job.pause,
|
116
|
+
'delete': job.delete,
|
119
117
|
}
|
120
118
|
if manage_job_action not in manage_functions:
|
121
119
|
return (
|
@@ -125,7 +123,7 @@ def manage_job_button_click(
|
|
125
123
|
dash.no_update,
|
126
124
|
)
|
127
125
|
|
128
|
-
old_status =
|
126
|
+
old_status = job.status
|
129
127
|
try:
|
130
128
|
success, msg = manage_functions[manage_job_action]()
|
131
129
|
except Exception as e:
|
@@ -136,15 +134,15 @@ def manage_job_button_click(
|
|
136
134
|
check_interval_seconds = 0.01
|
137
135
|
begin = time.perf_counter()
|
138
136
|
while (time.perf_counter() - begin) < timeout_seconds:
|
139
|
-
if
|
137
|
+
if job.status != old_status:
|
140
138
|
break
|
141
139
|
time.sleep(check_interval_seconds)
|
142
140
|
|
143
141
|
return (
|
144
142
|
alert_from_success_tuple((success, msg)),
|
145
|
-
build_manage_job_buttons_div_children(
|
146
|
-
build_status_children(
|
147
|
-
build_process_timestamps_children(
|
143
|
+
build_manage_job_buttons_div_children(job),
|
144
|
+
build_status_children(job),
|
145
|
+
build_process_timestamps_children(job),
|
148
146
|
)
|
149
147
|
|
150
148
|
dash_app.clientside_callback(
|
@@ -165,7 +163,7 @@ dash_app.clientside_callback(
|
|
165
163
|
}
|
166
164
|
|
167
165
|
const triggered_id = dash_clientside.callback_context.triggered_id;
|
168
|
-
const
|
166
|
+
const job_name = triggered_id["index"];
|
169
167
|
|
170
168
|
iframe = document.getElementById('webterm-iframe');
|
171
169
|
if (!iframe){ return dash_clientside.no_update; }
|
@@ -174,7 +172,7 @@ dash_app.clientside_callback(
|
|
174
172
|
{
|
175
173
|
action: "show",
|
176
174
|
subaction: "logs",
|
177
|
-
subaction_text:
|
175
|
+
subaction_text: job_name,
|
178
176
|
},
|
179
177
|
url
|
180
178
|
);
|
@@ -197,44 +195,38 @@ dash_app.clientside_callback(
|
|
197
195
|
prevent_initial_call = True,
|
198
196
|
)
|
199
197
|
def refresh_jobs_on_interval(
|
200
|
-
|
201
|
-
|
202
|
-
|
198
|
+
n_intervals: Optional[int] = None,
|
199
|
+
session_data: Optional[Dict[str, Any]] = None,
|
200
|
+
):
|
203
201
|
"""
|
204
202
|
When the jobs refresh interval fires, rebuild the jobs' onscreen components.
|
205
203
|
"""
|
206
204
|
session_id = session_data.get('session-id', None)
|
207
205
|
is_authenticated = is_session_authenticated(session_id)
|
208
206
|
|
209
|
-
|
207
|
+
job_names = [
|
210
208
|
component_dict['id']['index']
|
211
209
|
for component_dict in dash.callback_context.outputs_grouping[0]
|
212
210
|
]
|
213
211
|
|
214
|
-
### NOTE: The
|
215
|
-
|
216
|
-
for daemon_id in daemon_ids:
|
217
|
-
try:
|
218
|
-
daemon = Daemon(daemon_id=daemon_id)
|
219
|
-
except Exception as e:
|
220
|
-
daemon = None
|
221
|
-
daemons.append(daemon)
|
212
|
+
### NOTE: The job may have been deleted, but the card may still exist.
|
213
|
+
jobs = [Job(name) for name in job_names]
|
222
214
|
|
223
215
|
return (
|
224
216
|
[
|
225
217
|
(
|
226
|
-
build_manage_job_buttons_div_children(
|
218
|
+
build_manage_job_buttons_div_children(job)
|
227
219
|
if is_authenticated
|
228
220
|
else []
|
229
221
|
)
|
230
|
-
for
|
222
|
+
for job in jobs
|
231
223
|
],
|
232
224
|
[
|
233
|
-
build_status_children(
|
234
|
-
for
|
225
|
+
build_status_children(job)
|
226
|
+
for job in jobs
|
235
227
|
],
|
236
228
|
[
|
237
|
-
build_process_timestamps_children(
|
238
|
-
for
|
229
|
+
build_process_timestamps_children(job)
|
230
|
+
for job in jobs
|
239
231
|
],
|
240
232
|
)
|