meerschaum 2.4.11__py3-none-any.whl → 2.4.13__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/_parse_arguments.py +15 -1
- meerschaum/_internal/docs/index.py +1 -0
- meerschaum/_internal/entry.py +1 -0
- meerschaum/_internal/shell/Shell.py +19 -9
- meerschaum/_internal/shell/ShellCompleter.py +11 -6
- meerschaum/actions/bootstrap.py +119 -16
- meerschaum/actions/clear.py +41 -30
- meerschaum/actions/delete.py +1 -1
- meerschaum/actions/edit.py +118 -3
- meerschaum/actions/sh.py +11 -10
- meerschaum/actions/start.py +61 -4
- meerschaum/actions/sync.py +14 -16
- meerschaum/actions/upgrade.py +5 -4
- meerschaum/api/dash/callbacks/dashboard.py +2 -1
- meerschaum/api/dash/callbacks/jobs.py +53 -7
- meerschaum/api/dash/callbacks/pipes.py +1 -1
- meerschaum/api/dash/jobs.py +86 -60
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/job.py +21 -0
- meerschaum/api/routes/_jobs.py +3 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/sql/_fetch.py +67 -61
- meerschaum/connectors/sql/_pipes.py +36 -29
- meerschaum/plugins/__init__.py +6 -2
- meerschaum/plugins/bootstrap.py +15 -15
- meerschaum/utils/formatting/__init__.py +32 -16
- meerschaum/utils/formatting/_pipes.py +1 -1
- meerschaum/utils/formatting/_shell.py +4 -3
- meerschaum/utils/process.py +18 -8
- meerschaum/utils/prompt.py +16 -15
- meerschaum/utils/sql.py +107 -35
- meerschaum/utils/venv/__init__.py +35 -24
- meerschaum/utils/warnings.py +7 -7
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/METADATA +1 -1
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/RECORD +41 -40
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/WHEEL +1 -1
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/LICENSE +0 -0
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/NOTICE +0 -0
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/top_level.txt +0 -0
- {meerschaum-2.4.11.dist-info → meerschaum-2.4.13.dist-info}/zip-safe +0 -0
@@ -256,7 +256,8 @@ def parse_synonyms(
|
|
256
256
|
|
257
257
|
|
258
258
|
def parse_dict_to_sysargs(
|
259
|
-
args_dict: Dict[str, Any]
|
259
|
+
args_dict: Dict[str, Any],
|
260
|
+
coerce_dates: bool = True,
|
260
261
|
) -> List[str]:
|
261
262
|
"""Revert an arguments dictionary back to a command line list."""
|
262
263
|
import shlex
|
@@ -304,6 +305,19 @@ def parse_dict_to_sysargs(
|
|
304
305
|
if len(args_dict[a]) > 0:
|
305
306
|
sysargs += [t[0], json.dumps(args_dict[a], separators=(',', ':'))]
|
306
307
|
|
308
|
+
### Preserve the original datetime strings if possible
|
309
|
+
elif a in ('begin', 'end') and 'sysargs' in args_dict:
|
310
|
+
flag = t[0]
|
311
|
+
flag_ix = args_dict['sysargs'].index(flag)
|
312
|
+
if flag_ix < 0:
|
313
|
+
continue
|
314
|
+
try:
|
315
|
+
flag_val = args_dict['sysargs'][flag_ix + 1]
|
316
|
+
except IndexError:
|
317
|
+
flag_val = str(args_dict[a])
|
318
|
+
|
319
|
+
sysargs += [flag, str(flag_val)]
|
320
|
+
|
307
321
|
### Account for None and other values
|
308
322
|
elif (args_dict[a] is not None) or (args_dict[a] is None and a in allow_none_args):
|
309
323
|
sysargs += [t[0], str(args_dict[a])]
|
@@ -742,6 +742,7 @@ def init_dash(dash_app):
|
|
742
742
|
<li><code>meerschaum.utils.sql.get_db_version()</code></li>
|
743
743
|
<li><code>meerschaum.utils.sql.get_rename_table_queries()</code></li>
|
744
744
|
<li><code>meerschaum.utils.sql.get_create_table_query()</code></li>
|
745
|
+
<li><code>meerschaum.utils.sql.wrap_query_with_cte()</code></li>
|
745
746
|
<li><code>meerschaum.utils.sql.format_cte_subquery()</code></li>
|
746
747
|
<li><code>meerschaum.utils.sql.session_execute()</code></li>
|
747
748
|
</ul>
|
meerschaum/_internal/entry.py
CHANGED
@@ -235,6 +235,23 @@ def get_shell_intro(with_color: bool = True) -> str:
|
|
235
235
|
**get_config('shell', 'ansi', 'intro', 'rich')
|
236
236
|
)
|
237
237
|
|
238
|
+
def get_shell_session():
|
239
|
+
"""
|
240
|
+
Return the `prompt_toolkit` prompt session.
|
241
|
+
"""
|
242
|
+
from meerschaum.config._paths import SHELL_HISTORY_PATH
|
243
|
+
if 'session' in shell_attrs:
|
244
|
+
return shell_attrs['session']
|
245
|
+
|
246
|
+
shell_attrs['session'] = prompt_toolkit_shortcuts.PromptSession(
|
247
|
+
history=prompt_toolkit_history.FileHistory(SHELL_HISTORY_PATH.as_posix()),
|
248
|
+
auto_suggest=ValidAutoSuggest(),
|
249
|
+
completer=ShellCompleter(),
|
250
|
+
complete_while_typing=True,
|
251
|
+
reserve_space_for_menu=False,
|
252
|
+
)
|
253
|
+
return shell_attrs['session']
|
254
|
+
|
238
255
|
|
239
256
|
class Shell(cmd.Cmd):
|
240
257
|
"""
|
@@ -264,14 +281,7 @@ class Shell(cmd.Cmd):
|
|
264
281
|
except AttributeError:
|
265
282
|
pass
|
266
283
|
|
267
|
-
|
268
|
-
shell_attrs['session'] = prompt_toolkit_shortcuts.PromptSession(
|
269
|
-
history=prompt_toolkit_history.FileHistory(SHELL_HISTORY_PATH.as_posix()),
|
270
|
-
auto_suggest=ValidAutoSuggest(),
|
271
|
-
completer=ShellCompleter(),
|
272
|
-
complete_while_typing=True,
|
273
|
-
reserve_space_for_menu=False,
|
274
|
-
)
|
284
|
+
_ = get_shell_session()
|
275
285
|
|
276
286
|
super().__init__()
|
277
287
|
|
@@ -626,7 +636,7 @@ class Shell(cmd.Cmd):
|
|
626
636
|
step_action_name = step_action[0] if step_action else None
|
627
637
|
### NOTE: For `stack`, revert argument parsing.
|
628
638
|
step_sysargs = (
|
629
|
-
parse_dict_to_sysargs(step_kwargs)
|
639
|
+
parse_dict_to_sysargs(step_kwargs, coerce_dates=False)
|
630
640
|
if step_action_name != 'stack'
|
631
641
|
else chained_sysargs[i]
|
632
642
|
)
|
@@ -31,15 +31,18 @@ class ShellCompleter(Completer):
|
|
31
31
|
ensure_readline()
|
32
32
|
parts = document.text.split('-')
|
33
33
|
ends_with_space = parts[0].endswith(' ')
|
34
|
-
|
35
|
-
|
34
|
+
last_action_line = parts[0].split('+')[-1]
|
35
|
+
part_0_subbed_spaces = last_action_line.replace(' ', '_')
|
36
|
+
parsed_text = (part_0_subbed_spaces + '-'.join(parts[1:]))
|
36
37
|
|
38
|
+
if not parsed_text:
|
39
|
+
return
|
37
40
|
|
38
41
|
### Index is the rank order (0 is closest match).
|
39
42
|
### Break when no results are returned.
|
40
43
|
for i, a in enumerate(shell_actions):
|
41
44
|
try:
|
42
|
-
poss = shell.complete(parsed_text, i)
|
45
|
+
poss = shell.complete(parsed_text.lstrip('_'), i)
|
43
46
|
if poss:
|
44
47
|
poss = poss.replace('_', ' ')
|
45
48
|
### Having issues with readline on portable Windows.
|
@@ -50,7 +53,9 @@ class ShellCompleter(Completer):
|
|
50
53
|
yield Completion(poss, start_position=(-1 * len(poss)))
|
51
54
|
yielded.append(poss)
|
52
55
|
|
53
|
-
|
56
|
+
line = document.text
|
57
|
+
current_action_line = line.split('+')[-1].lstrip()
|
58
|
+
args = parse_line(current_action_line)
|
54
59
|
action_function = get_action(args['action'], _actions=shell_attrs.get('_actions', None))
|
55
60
|
if action_function is None:
|
56
61
|
return
|
@@ -74,8 +79,8 @@ class ShellCompleter(Completer):
|
|
74
79
|
shell,
|
75
80
|
complete_function_name
|
76
81
|
)(
|
77
|
-
|
78
|
-
|
82
|
+
current_action_line.split(' ')[-1],
|
83
|
+
current_action_line,
|
79
84
|
0,
|
80
85
|
0
|
81
86
|
)
|
meerschaum/actions/bootstrap.py
CHANGED
@@ -8,15 +8,18 @@ Functions for bootstrapping elements
|
|
8
8
|
"""
|
9
9
|
|
10
10
|
from __future__ import annotations
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
11
13
|
from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
|
12
14
|
|
15
|
+
|
13
16
|
def bootstrap(
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
action: Optional[List[str]] = None,
|
18
|
+
**kw: Any
|
19
|
+
) -> SuccessTuple:
|
17
20
|
"""
|
18
21
|
Launch an interactive wizard to bootstrap pipes or connectors.
|
19
|
-
|
22
|
+
|
20
23
|
Example:
|
21
24
|
`bootstrap pipes`
|
22
25
|
|
@@ -26,23 +29,24 @@ def bootstrap(
|
|
26
29
|
'pipes' : _bootstrap_pipes,
|
27
30
|
'connectors' : _bootstrap_connectors,
|
28
31
|
'plugins' : _bootstrap_plugins,
|
32
|
+
'jobs' : _bootstrap_jobs,
|
29
33
|
}
|
30
34
|
return choose_subaction(action, options, **kw)
|
31
35
|
|
32
36
|
|
33
37
|
def _bootstrap_pipes(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
action: Optional[List[str]] = None,
|
39
|
+
connector_keys: Optional[List[str]] = None,
|
40
|
+
metric_keys: Optional[List[str]] = None,
|
41
|
+
location_keys: Optional[List[Optional[str]]] = None,
|
42
|
+
yes: bool = False,
|
43
|
+
force: bool = False,
|
44
|
+
noask: bool = False,
|
45
|
+
debug: bool = False,
|
46
|
+
mrsm_instance: Optional[str] = None,
|
47
|
+
shell: bool = False,
|
48
|
+
**kw: Any
|
49
|
+
) -> SuccessTuple:
|
46
50
|
"""
|
47
51
|
Create a new pipe.
|
48
52
|
If no keys are provided, guide the user through the steps required.
|
@@ -433,6 +437,105 @@ def _bootstrap_plugins(
|
|
433
437
|
return True, "Success"
|
434
438
|
|
435
439
|
|
440
|
+
def _bootstrap_jobs(
|
441
|
+
action: Optional[List[str]] = None,
|
442
|
+
executor_keys: Optional[str] = None,
|
443
|
+
debug: bool = False,
|
444
|
+
**kwargs: Any
|
445
|
+
) -> SuccessTuple:
|
446
|
+
"""
|
447
|
+
Launch an interactive wizard to create new jobs.
|
448
|
+
"""
|
449
|
+
import shlex
|
450
|
+
from meerschaum.utils.prompt import prompt, yes_no
|
451
|
+
from meerschaum.actions import actions
|
452
|
+
from meerschaum.utils.formatting import print_options, make_header
|
453
|
+
from meerschaum.utils.formatting._shell import clear_screen
|
454
|
+
from meerschaum.utils.warnings import info
|
455
|
+
from meerschaum._internal.arguments import (
|
456
|
+
split_pipeline_sysargs,
|
457
|
+
split_chained_sysargs,
|
458
|
+
)
|
459
|
+
from meerschaum.utils.misc import items_str
|
460
|
+
from meerschaum._internal.shell.ShellCompleter import ShellCompleter
|
461
|
+
|
462
|
+
if not action:
|
463
|
+
action = [prompt("What is the name of the job you'd like to create?")]
|
464
|
+
|
465
|
+
for name in action:
|
466
|
+
clear_screen(debug=debug)
|
467
|
+
job = mrsm.Job(name, executor_keys=executor_keys)
|
468
|
+
if job.exists():
|
469
|
+
edit_success, edit_msg = actions['edit'](['job', name], **kwargs)
|
470
|
+
if not edit_success:
|
471
|
+
return edit_success, edit_msg
|
472
|
+
continue
|
473
|
+
|
474
|
+
info(
|
475
|
+
f"Editing arguments for job '{name}'.\n"
|
476
|
+
" Press [Esc + Enter] to submit, [CTRL + C] to exit.\n\n"
|
477
|
+
" Tip: join multiple actions with `+`, add pipeline arguments with `:`.\n"
|
478
|
+
" https://meerschaum.io/reference/actions/#chaining-actions\n"
|
479
|
+
)
|
480
|
+
try:
|
481
|
+
new_sysargs_str = prompt(
|
482
|
+
"",
|
483
|
+
multiline=True,
|
484
|
+
icon=False,
|
485
|
+
completer=ShellCompleter(),
|
486
|
+
)
|
487
|
+
except KeyboardInterrupt:
|
488
|
+
return True, "Nothing was changed."
|
489
|
+
|
490
|
+
new_sysargs = shlex.split(new_sysargs_str)
|
491
|
+
new_sysargs, pipeline_args = split_pipeline_sysargs(new_sysargs)
|
492
|
+
chained_sysargs = split_chained_sysargs(new_sysargs)
|
493
|
+
|
494
|
+
clear_screen(debug=debug)
|
495
|
+
if len(chained_sysargs) > 1:
|
496
|
+
print_options(
|
497
|
+
[
|
498
|
+
shlex.join(step_sysargs)
|
499
|
+
for step_sysargs in chained_sysargs
|
500
|
+
],
|
501
|
+
header=f"Steps in Job '{name}':",
|
502
|
+
number_options=True,
|
503
|
+
**kwargs
|
504
|
+
)
|
505
|
+
else:
|
506
|
+
print('\n' + make_header(f"Action for Job '{name}':"))
|
507
|
+
print(shlex.join(new_sysargs))
|
508
|
+
|
509
|
+
if pipeline_args:
|
510
|
+
print('\n' + make_header("Pipeline Arguments:"))
|
511
|
+
print(shlex.join(pipeline_args))
|
512
|
+
print()
|
513
|
+
|
514
|
+
if not yes_no(
|
515
|
+
(
|
516
|
+
f"Are you sure you want to create job '{name}' with the above arguments?\n"
|
517
|
+
+ " The job will be started if you continue."
|
518
|
+
),
|
519
|
+
default='n',
|
520
|
+
**kwargs
|
521
|
+
):
|
522
|
+
return True, "Nothing was changed."
|
523
|
+
|
524
|
+
new_job = mrsm.Job(name, new_sysargs_str, executor_keys=executor_keys)
|
525
|
+
start_success, start_msg = new_job.start()
|
526
|
+
if not start_success:
|
527
|
+
return start_success, start_msg
|
528
|
+
|
529
|
+
msg = (
|
530
|
+
"Successfully bootstrapped job"
|
531
|
+
+ ('s' if len(action) != 1 else '')
|
532
|
+
+ ' '
|
533
|
+
+ items_str(action)
|
534
|
+
+ '.'
|
535
|
+
)
|
536
|
+
return True, msg
|
537
|
+
|
538
|
+
|
436
539
|
### NOTE: This must be the final statement of the module.
|
437
540
|
### Any subactions added below these lines will not
|
438
541
|
### be added to the `help` docstring.
|
meerschaum/actions/clear.py
CHANGED
@@ -6,12 +6,16 @@ Functions for clearing pipes.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from __future__ import annotations
|
9
|
+
|
10
|
+
from datetime import datetime
|
11
|
+
import meerschaum as mrsm
|
9
12
|
from meerschaum.utils.typing import List, SuccessTuple, Any, Optional
|
10
13
|
|
14
|
+
|
11
15
|
def clear(
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
action: Optional[List[str]] = None,
|
17
|
+
**kw: Any
|
18
|
+
) -> SuccessTuple:
|
15
19
|
"""
|
16
20
|
Clear pipes of their data, or clear the screen.
|
17
21
|
|
@@ -34,24 +38,25 @@ def clear(
|
|
34
38
|
|
35
39
|
|
36
40
|
def _clear_pipes(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
action: Optional[List[str]] = None,
|
42
|
+
begin: Optional[datetime] = None,
|
43
|
+
end: Optional[datetime] = None,
|
44
|
+
connector_keys: Optional[List[str]] = None,
|
45
|
+
metric_keys: Optional[List[str]] = None,
|
46
|
+
mrsm_instance: Optional[str] = None,
|
47
|
+
location_keys: Optional[List[str]] = None,
|
48
|
+
yes: bool = False,
|
49
|
+
force: bool = False,
|
50
|
+
debug: bool = False,
|
51
|
+
**kw: Any
|
52
|
+
) -> SuccessTuple:
|
48
53
|
"""
|
49
54
|
Clear pipes' data without dropping any tables.
|
50
55
|
|
51
56
|
"""
|
52
57
|
from meerschaum import get_pipes
|
53
58
|
from meerschaum.utils.formatting import print_tuple
|
54
|
-
|
59
|
+
|
55
60
|
successes = {}
|
56
61
|
fails = {}
|
57
62
|
|
@@ -61,13 +66,19 @@ def _clear_pipes(
|
|
61
66
|
)
|
62
67
|
|
63
68
|
if not force:
|
64
|
-
if not _ask_with_rowcounts(pipes, begin=begin, end=end, debug=debug, **kw):
|
69
|
+
if not _ask_with_rowcounts(pipes, begin=begin, end=end, debug=debug, yes=yes, **kw):
|
65
70
|
return False, "No rows were deleted."
|
66
71
|
|
67
72
|
for pipe in pipes:
|
68
|
-
|
69
|
-
|
70
|
-
|
73
|
+
clear_success, clear_msg = pipe.clear(
|
74
|
+
begin=begin,
|
75
|
+
end=end,
|
76
|
+
yes=yes,
|
77
|
+
debug=debug,
|
78
|
+
**kw
|
79
|
+
)
|
80
|
+
print_tuple((clear_success, clear_msg))
|
81
|
+
(successes if clear_success else fails)[pipe] = clear_msg
|
71
82
|
|
72
83
|
success = len(successes) > 0
|
73
84
|
msg = (
|
@@ -79,15 +90,15 @@ def _clear_pipes(
|
|
79
90
|
|
80
91
|
|
81
92
|
def _ask_with_rowcounts(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
93
|
+
pipes: List[mrsm.Pipe],
|
94
|
+
begin: Optional[datetime] = None,
|
95
|
+
end: Optional[datetime] = None,
|
96
|
+
yes: bool = False,
|
97
|
+
nopretty: bool = False,
|
98
|
+
noask: bool = False,
|
99
|
+
debug: bool = False,
|
100
|
+
**kw
|
101
|
+
) -> bool:
|
91
102
|
"""
|
92
103
|
Count all of the pipes' rowcounts and confirm with the user that these rows need to be deleted.
|
93
104
|
|
@@ -109,13 +120,13 @@ def _ask_with_rowcounts(
|
|
109
120
|
warn(
|
110
121
|
f"No datetime could be determined for {pipe}!\n"
|
111
122
|
+ " THIS WILL DELETE THE ENTIRE TABLE!",
|
112
|
-
stack
|
123
|
+
stack=False
|
113
124
|
)
|
114
125
|
else:
|
115
126
|
warn(
|
116
127
|
f"A datetime wasn't specified for {pipe}.\n"
|
117
128
|
+ f" Using column \"{_dt}\" for datetime bounds...",
|
118
|
-
stack
|
129
|
+
stack=False
|
119
130
|
)
|
120
131
|
|
121
132
|
|
meerschaum/actions/delete.py
CHANGED
@@ -498,7 +498,7 @@ def _complete_delete_jobs(
|
|
498
498
|
action: Optional[List[str]] = None,
|
499
499
|
executor_keys: Optional[str] = None,
|
500
500
|
line: str = '',
|
501
|
-
_get_job_method:
|
501
|
+
_get_job_method: Union[str, List[str], None] = None,
|
502
502
|
**kw
|
503
503
|
) -> List[str]:
|
504
504
|
from meerschaum._internal.shell.Shell import shell_attrs
|
meerschaum/actions/edit.py
CHANGED
@@ -7,9 +7,11 @@ Functions for editing elements belong here.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
10
11
|
import meerschaum as mrsm
|
11
12
|
from meerschaum.utils.typing import List, Any, SuccessTuple, Optional, Dict
|
12
13
|
|
14
|
+
|
13
15
|
def edit(
|
14
16
|
action: Optional[List[str]] = None,
|
15
17
|
**kw: Any
|
@@ -24,6 +26,7 @@ def edit(
|
|
24
26
|
'definition': _edit_definition,
|
25
27
|
'users' : _edit_users,
|
26
28
|
'plugins' : _edit_plugins,
|
29
|
+
'jobs' : _edit_jobs,
|
27
30
|
}
|
28
31
|
return choose_subaction(action, options, **kw)
|
29
32
|
|
@@ -35,10 +38,17 @@ def _complete_edit(
|
|
35
38
|
"""
|
36
39
|
Override the default Meerschaum `complete_` function.
|
37
40
|
"""
|
41
|
+
from meerschaum.actions.delete import _complete_delete_jobs
|
42
|
+
|
43
|
+
if action is None:
|
44
|
+
action = []
|
45
|
+
|
38
46
|
options = {
|
39
47
|
'config': _complete_edit_config,
|
40
48
|
'plugin': _complete_edit_plugins,
|
41
49
|
'plugins': _complete_edit_plugins,
|
50
|
+
'job': _complete_delete_jobs,
|
51
|
+
'jobs': _complete_delete_jobs,
|
42
52
|
}
|
43
53
|
|
44
54
|
if action is None:
|
@@ -130,7 +140,7 @@ def _edit_pipes(
|
|
130
140
|
|
131
141
|
pipes = get_pipes(debug=debug, as_list=True, **kw)
|
132
142
|
if pipes:
|
133
|
-
print_options(pipes, header=
|
143
|
+
print_options(pipes, header='Pipes to be edited:')
|
134
144
|
else:
|
135
145
|
return False, "No pipes to edit."
|
136
146
|
|
@@ -141,10 +151,10 @@ def _edit_pipes(
|
|
141
151
|
f"Press [Enter] to begin editing the above {len(pipes)} pipe"
|
142
152
|
+ ("s" if len(pipes) != 1 else "")
|
143
153
|
+ " or [CTRL-C] to cancel:",
|
144
|
-
icon
|
154
|
+
icon=False,
|
145
155
|
)
|
146
156
|
except KeyboardInterrupt:
|
147
|
-
return False,
|
157
|
+
return False, "No pipes changed."
|
148
158
|
|
149
159
|
interactive = (not bool(params))
|
150
160
|
success, msg = True, ""
|
@@ -372,6 +382,111 @@ def _complete_edit_plugins(
|
|
372
382
|
return possibilities
|
373
383
|
|
374
384
|
|
385
|
+
def _edit_jobs(
|
386
|
+
action: Optional[List[str]] = None,
|
387
|
+
executor_keys: Optional[str] = None,
|
388
|
+
debug: bool = False,
|
389
|
+
**kwargs: Any
|
390
|
+
) -> mrsm.SuccessTuple:
|
391
|
+
"""
|
392
|
+
Edit existing jobs.
|
393
|
+
"""
|
394
|
+
import shlex
|
395
|
+
from meerschaum.jobs import get_filtered_jobs
|
396
|
+
from meerschaum.utils.prompt import prompt, yes_no
|
397
|
+
from meerschaum._internal.arguments import (
|
398
|
+
split_pipeline_sysargs,
|
399
|
+
split_chained_sysargs,
|
400
|
+
)
|
401
|
+
from meerschaum.utils.formatting import make_header, print_options
|
402
|
+
from meerschaum.utils.warnings import info
|
403
|
+
from meerschaum._internal.shell.ShellCompleter import ShellCompleter
|
404
|
+
from meerschaum.utils.misc import items_str
|
405
|
+
from meerschaum.utils.formatting._shell import clear_screen
|
406
|
+
|
407
|
+
jobs = get_filtered_jobs(executor_keys, action, debug=debug)
|
408
|
+
if not jobs:
|
409
|
+
return False, "No jobs to edit."
|
410
|
+
|
411
|
+
num_edited = 0
|
412
|
+
for name, job in jobs.items():
|
413
|
+
sysargs_str = shlex.join(job.sysargs)
|
414
|
+
clear_screen(debug=debug)
|
415
|
+
info(
|
416
|
+
f"Editing arguments for job '{name}'.\n"
|
417
|
+
" Press [Esc + Enter] to submit, [CTRL + C] to exit.\n\n"
|
418
|
+
" Tip: join actions with `+`, manage pipeline with `:`.\n"
|
419
|
+
" https://meerschaum.io/reference/actions/#chaining-actions\n"
|
420
|
+
)
|
421
|
+
|
422
|
+
try:
|
423
|
+
new_sysargs_str = prompt(
|
424
|
+
"",
|
425
|
+
default_editable=sysargs_str.lstrip().rstrip().replace(' + ', '\n+ '),
|
426
|
+
multiline=True,
|
427
|
+
icon=False,
|
428
|
+
completer=ShellCompleter(),
|
429
|
+
)
|
430
|
+
except KeyboardInterrupt:
|
431
|
+
return True, "Nothing was changed."
|
432
|
+
|
433
|
+
if new_sysargs_str.strip() == sysargs_str.strip():
|
434
|
+
continue
|
435
|
+
|
436
|
+
new_sysargs = shlex.split(new_sysargs_str)
|
437
|
+
new_sysargs, pipeline_args = split_pipeline_sysargs(new_sysargs)
|
438
|
+
chained_sysargs = split_chained_sysargs(new_sysargs)
|
439
|
+
|
440
|
+
clear_screen(debug=debug)
|
441
|
+
if len(chained_sysargs) > 1:
|
442
|
+
print_options(
|
443
|
+
[
|
444
|
+
shlex.join(step_sysargs)
|
445
|
+
for step_sysargs in chained_sysargs
|
446
|
+
],
|
447
|
+
header=f"\nSteps in Job '{name}':",
|
448
|
+
number_options=True,
|
449
|
+
**kwargs
|
450
|
+
)
|
451
|
+
else:
|
452
|
+
print('\n' + make_header(f"Action for Job '{name}':"))
|
453
|
+
print(shlex.join(new_sysargs))
|
454
|
+
|
455
|
+
if pipeline_args:
|
456
|
+
print('\n' + make_header("Pipeline Arguments:"))
|
457
|
+
print(shlex.join(pipeline_args))
|
458
|
+
print()
|
459
|
+
|
460
|
+
if not yes_no(
|
461
|
+
(
|
462
|
+
f"Are you sure you want to recreate job '{name}' with the above arguments?\n"
|
463
|
+
+ " The job will be started if you continue."
|
464
|
+
),
|
465
|
+
default='n',
|
466
|
+
**kwargs
|
467
|
+
):
|
468
|
+
return True, "Nothing was changed."
|
469
|
+
|
470
|
+
delete_success, delete_msg = job.delete()
|
471
|
+
if not delete_success:
|
472
|
+
return delete_success, delete_msg
|
473
|
+
|
474
|
+
new_job = mrsm.Job(name, new_sysargs_str, executor_keys=executor_keys)
|
475
|
+
start_success, start_msg = new_job.start()
|
476
|
+
if not start_success:
|
477
|
+
return start_success, start_msg
|
478
|
+
num_edited += 1
|
479
|
+
|
480
|
+
msg = (
|
481
|
+
"Successfully edit job"
|
482
|
+
+ ('s' if len(jobs) != 1 else '')
|
483
|
+
+ ' '
|
484
|
+
+ items_str(list(jobs.keys()))
|
485
|
+
+ '.'
|
486
|
+
) if num_edited > 0 else "Nothing was edited."
|
487
|
+
return True, msg
|
488
|
+
|
489
|
+
|
375
490
|
### NOTE: This must be the final statement of the module.
|
376
491
|
### Any subactions added below these lines will not
|
377
492
|
### be added to the `help` docstring.
|
meerschaum/actions/sh.py
CHANGED
@@ -9,14 +9,15 @@ NOTE: This action may be a huge security vulnerability
|
|
9
9
|
|
10
10
|
from meerschaum.utils.typing import SuccessTuple, List, Any, Optional
|
11
11
|
|
12
|
+
|
12
13
|
def sh(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
action: Optional[List[str]] = None,
|
15
|
+
sub_args: Optional[List[str]] = None,
|
16
|
+
filtered_sysargs: Optional[List[str]] = None,
|
17
|
+
use_bash: bool = True,
|
18
|
+
debug: bool = False,
|
19
|
+
**kw: Any
|
20
|
+
) -> SuccessTuple:
|
20
21
|
"""
|
21
22
|
Execute system commands.
|
22
23
|
"""
|
@@ -50,7 +51,7 @@ def sh(
|
|
50
51
|
if len(action) != 0:
|
51
52
|
try:
|
52
53
|
command_list += ["-c", shlex.join(cmd_list)]
|
53
|
-
except Exception
|
54
|
+
except Exception:
|
54
55
|
command_list += ["-c", ' '.join(cmd_list)]
|
55
56
|
else:
|
56
57
|
if len(action) == 0:
|
@@ -64,8 +65,8 @@ def sh(
|
|
64
65
|
try:
|
65
66
|
process = subprocess.Popen(
|
66
67
|
command_list,
|
67
|
-
shell
|
68
|
-
env
|
68
|
+
shell=False,
|
69
|
+
env=os.environ,
|
69
70
|
)
|
70
71
|
exit_code = process.wait()
|
71
72
|
except FileNotFoundError:
|