meerschaum 2.3.0rc3__py3-none-any.whl → 2.3.1__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.
Files changed (34) hide show
  1. meerschaum/__init__.py +2 -3
  2. meerschaum/_internal/arguments/__init__.py +1 -1
  3. meerschaum/_internal/arguments/_parse_arguments.py +33 -22
  4. meerschaum/_internal/arguments/_parser.py +4 -7
  5. meerschaum/_internal/docs/index.py +265 -8
  6. meerschaum/_internal/entry.py +42 -4
  7. meerschaum/_internal/shell/Shell.py +84 -72
  8. meerschaum/actions/__init__.py +21 -11
  9. meerschaum/actions/show.py +5 -5
  10. meerschaum/actions/start.py +71 -1
  11. meerschaum/api/routes/_actions.py +48 -1
  12. meerschaum/config/_paths.py +1 -0
  13. meerschaum/config/_version.py +1 -1
  14. meerschaum/config/static/__init__.py +2 -0
  15. meerschaum/connectors/__init__.py +1 -2
  16. meerschaum/connectors/api/APIConnector.py +6 -1
  17. meerschaum/connectors/api/_actions.py +77 -1
  18. meerschaum/connectors/api/_pipes.py +85 -84
  19. meerschaum/jobs/_Job.py +38 -6
  20. meerschaum/jobs/__init__.py +5 -3
  21. meerschaum/jobs/{_SystemdExecutor.py → systemd.py} +39 -22
  22. meerschaum/plugins/_Plugin.py +1 -1
  23. meerschaum/plugins/__init__.py +2 -1
  24. meerschaum/utils/daemon/StdinFile.py +1 -0
  25. meerschaum/utils/daemon/_names.py +14 -12
  26. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/METADATA +1 -1
  27. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/RECORD +33 -34
  28. meerschaum/jobs/_LocalExecutor.py +0 -88
  29. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/LICENSE +0 -0
  30. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/NOTICE +0 -0
  31. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/WHEEL +0 -0
  32. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/entry_points.txt +0 -0
  33. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/top_level.txt +0 -0
  34. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/zip-safe +0 -0
@@ -9,6 +9,7 @@ from __future__ import annotations
9
9
  import os
10
10
  from copy import deepcopy
11
11
  from itertools import chain
12
+ import shlex
12
13
 
13
14
  from meerschaum.utils.typing import Union, SuccessTuple, Any, Callable, Optional, List, Dict
14
15
  from meerschaum.utils.packages import attempt_import
@@ -31,12 +32,15 @@ from meerschaum._internal.shell.ValidAutoSuggest import ValidAutoSuggest
31
32
  from meerschaum._internal.shell.ShellCompleter import ShellCompleter
32
33
  _clear_screen = get_config('shell', 'clear_screen', patch=True)
33
34
  from meerschaum.utils.misc import string_width, remove_ansi
35
+ from meerschaum.utils.warnings import warn
34
36
  from meerschaum.jobs import get_executor_keys_from_context
35
37
  from meerschaum.config.static import STATIC_CONFIG
36
38
  from meerschaum._internal.arguments._parse_arguments import (
37
39
  split_chained_sysargs,
40
+ split_pipeline_sysargs,
38
41
  parse_arguments,
39
42
  parse_line,
43
+ parse_dict_to_sysargs,
40
44
  )
41
45
 
42
46
  patch = True
@@ -73,6 +77,8 @@ reserved_completers = {
73
77
  shell_attrs = {}
74
78
  AND_KEY: str = STATIC_CONFIG['system']['arguments']['and_key']
75
79
  ESCAPED_AND_KEY: str = STATIC_CONFIG['system']['arguments']['escaped_and_key']
80
+ PIPELINE_KEY: str = STATIC_CONFIG['system']['arguments']['pipeline_key']
81
+ ESCAPED_PIPELINE_KEY: str = STATIC_CONFIG['system']['arguments']['escaped_pipeline_key']
76
82
 
77
83
  def _insert_shell_actions(
78
84
  _shell: Optional['Shell'] = None,
@@ -173,7 +179,6 @@ def _check_complete_keys(line: str) -> Optional[List[str]]:
173
179
 
174
180
  ### TODO Find out arg possibilities
175
181
  possibilities = []
176
- # last_word = line.split(' ')[-1]
177
182
  last_word = line.rstrip(' ').split(' ')[-1]
178
183
 
179
184
  if last_word.startswith('-'):
@@ -485,6 +490,9 @@ class Shell(cmd.Cmd):
485
490
  ### make a backup of line for later
486
491
  original_line = deepcopy(line)
487
492
 
493
+ ### Escape backslashes to allow for multi-line input.
494
+ line = line.replace('\\\n', ' ')
495
+
488
496
  ### cmd2 support: check if command exists
489
497
  try:
490
498
  command = line.command
@@ -515,48 +523,71 @@ class Shell(cmd.Cmd):
515
523
  return "help " + line[len(help_token):]
516
524
 
517
525
  from meerschaum._internal.arguments import parse_line
518
- args = parse_line(line)
519
- if args.get('help', False):
526
+ try:
527
+ sysargs = shlex.split(line)
528
+ except ValueError as e:
529
+ warn(e, stack=False)
530
+ return ""
531
+
532
+ sysargs, pipeline_args = split_pipeline_sysargs(sysargs)
533
+ chained_sysargs = split_chained_sysargs(sysargs)
534
+ chained_kwargs = [
535
+ parse_arguments(_sysargs)
536
+ for _sysargs in chained_sysargs
537
+ ]
538
+
539
+ if '--help' in sysargs or '-h' in sysargs:
520
540
  from meerschaum._internal.arguments._parser import parse_help
521
- parse_help(args)
541
+ parse_help(sysargs)
522
542
  return ""
523
543
 
544
+ patch_args: Dict[str, Any] = {}
545
+
524
546
  ### NOTE: pass `shell` flag in case actions need to distinguish between
525
547
  ### being run on the command line and being run in the shell
526
- args['shell'] = True
527
- args['line'] = line
548
+ patch_args.update({
549
+ 'shell': True,
550
+ 'line': line,
551
+ })
552
+ patches: List[Dict[str, Any]] = [{} for _ in chained_kwargs]
528
553
 
529
554
  ### if debug is not set on the command line,
530
555
  ### default to shell setting
531
- if not args.get('debug', False):
532
- args['debug'] = shell_attrs['debug']
556
+ for kwargs in chained_kwargs:
557
+ if not kwargs.get('debug', False):
558
+ kwargs['debug'] = shell_attrs['debug']
533
559
 
534
560
  ### Make sure an action was provided.
535
- if not args.get('action', None):
561
+ if (
562
+ not chained_kwargs
563
+ or not chained_kwargs[0].get('action', None)
564
+ ):
536
565
  self.emptyline()
537
566
  return ''
538
567
 
539
568
  ### Strip a leading 'mrsm' if it's provided.
540
- if args['action'][0] == 'mrsm':
541
- args['action'] = args['action'][1:]
542
- if not args['action']:
543
- self.emptyline()
544
- return ''
569
+ for kwargs in chained_kwargs:
570
+ if kwargs['action'][0] == 'mrsm':
571
+ kwargs['action'] = kwargs['action'][1:]
572
+ if not kwargs['action']:
573
+ self.emptyline()
574
+ return ''
545
575
 
546
576
  ### If we don't recognize the action,
547
577
  ### make it a shell action.
548
- from meerschaum.actions import get_main_action_name
549
- main_action_name = get_main_action_name(args['action'])
550
- if main_action_name is None:
551
- if not hasattr(self, 'do_' + args['action'][0]):
552
- args['action'].insert(0, 'sh')
553
- main_action_name = 'sh'
554
- else:
555
- main_action_name = args['action'][0]
556
-
557
- def _add_flag_to_sysargs(
558
- chained_sysargs, key, value, flag, shell_key=None,
559
- ):
578
+ ### TODO: make this work for chained actions
579
+ def _get_main_action_name(kwargs):
580
+ from meerschaum.actions import get_main_action_name
581
+ main_action_name = get_main_action_name(kwargs['action'])
582
+ if main_action_name is None:
583
+ if not hasattr(self, 'do_' + kwargs['action'][0]):
584
+ kwargs['action'].insert(0, 'sh')
585
+ main_action_name = 'sh'
586
+ else:
587
+ main_action_name = kwargs['action'][0]
588
+ return main_action_name
589
+
590
+ def _add_flag_to_kwargs(kwargs, i, key, shell_key=None):
560
591
  shell_key = shell_key or key
561
592
  shell_value = remove_ansi(shell_attrs.get(shell_key) or '')
562
593
  if key == 'mrsm_instance':
@@ -568,68 +599,49 @@ class Shell(cmd.Cmd):
568
599
  else:
569
600
  default_value = None
570
601
 
571
- if shell_value == default_value:
602
+ if key in kwargs or shell_value == default_value:
572
603
  return
573
604
 
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
-
605
+ patches[i][key] = shell_value
587
606
 
588
607
  ### if no instance is provided, use current shell default,
589
608
  ### but not for the 'api' command (to avoid recursion)
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
- )
601
-
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
- )
609
+ for i, kwargs in enumerate(chained_kwargs):
610
+ main_action_name = _get_main_action_name(kwargs)
611
+ if main_action_name == 'api':
612
+ continue
610
613
 
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
- )
614
+ _add_flag_to_kwargs(kwargs, i, 'mrsm_instance', shell_key='instance_keys')
615
+ _add_flag_to_kwargs(kwargs, i, 'repository', shell_key='repo_keys')
616
+ _add_flag_to_kwargs(kwargs, i, 'executor_keys')
619
617
 
620
618
  ### parse out empty strings
621
- if args['action'][0].strip("\"'") == '':
619
+ if chained_kwargs[0]['action'][0].strip("\"'") == '':
622
620
  self.emptyline()
623
621
  return ""
624
622
 
625
- positional_only = (main_action_name not in shell_attrs['_actions'])
623
+ positional_only = (_get_main_action_name(chained_kwargs[0]) not in shell_attrs['_actions'])
626
624
  if positional_only:
627
625
  return original_line
628
626
 
629
- from meerschaum._internal.entry import entry_with_args
627
+ ### Apply patch to all kwargs.
628
+ for i, kwargs in enumerate([_ for _ in chained_kwargs]):
629
+ kwargs.update(patches[i])
630
+
631
+ from meerschaum._internal.entry import entry_with_args, entry
632
+ sysargs_to_execute = []
633
+ for i, kwargs in enumerate(chained_kwargs):
634
+ step_kwargs = {k: v for k, v in kwargs.items() if k != 'line'}
635
+ step_sysargs = parse_dict_to_sysargs(step_kwargs)
636
+ sysargs_to_execute.extend(step_sysargs)
637
+ sysargs_to_execute.append(AND_KEY)
638
+
639
+ sysargs_to_execute = sysargs_to_execute[:-1] + (
640
+ ([':'] + pipeline_args) if pipeline_args else []
641
+ )
630
642
 
631
643
  try:
632
- success_tuple = entry_with_args(_actions=shell_attrs['_actions'], **args)
644
+ success_tuple = entry(sysargs_to_execute, _patch_args=patch_args)
633
645
  except Exception as e:
634
646
  success_tuple = False, str(e)
635
647
 
@@ -11,6 +11,16 @@ from meerschaum.utils.typing import Callable, Any, Optional, Union, List, Dict,
11
11
  from meerschaum.utils.packages import get_modules_from_package
12
12
  _custom_actions = []
13
13
 
14
+ __all__ = (
15
+ 'get_action',
16
+ 'get_subactions',
17
+ 'make_action',
18
+ 'pre_sync_hook',
19
+ 'post_sync_hook',
20
+ 'get_main_action_name',
21
+ 'get_completer',
22
+ )
23
+
14
24
  def get_subactions(
15
25
  action: Union[str, List[str]],
16
26
  _actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
@@ -101,9 +111,9 @@ def get_action(
101
111
 
102
112
 
103
113
  def get_main_action_name(
104
- action: Union[List[str], str],
105
- _actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
106
- ) -> Union[str, None]:
114
+ action: Union[List[str], str],
115
+ _actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
116
+ ) -> Union[str, None]:
107
117
  """
108
118
  Given an action list, return the name of the main function.
109
119
  For subactions, this will return the root function.
@@ -140,9 +150,9 @@ def get_main_action_name(
140
150
 
141
151
 
142
152
  def get_completer(
143
- action: Union[List[str], str],
144
- _actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
145
- ) -> Union[
153
+ action: Union[List[str], str],
154
+ _actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
155
+ ) -> Union[
146
156
  Callable[['meerschaum._internal.shell.Shell', str, str, int, int], List[str]], None
147
157
  ]:
148
158
  """Search for a custom completer function for an action."""
@@ -179,10 +189,10 @@ def get_completer(
179
189
 
180
190
 
181
191
  def choose_subaction(
182
- action: Optional[List[str]] = None,
183
- options: Optional[Dict[str, Any]] = None,
184
- **kw
185
- ) -> SuccessTuple:
192
+ action: Optional[List[str]] = None,
193
+ options: Optional[Dict[str, Any]] = None,
194
+ **kw
195
+ ) -> SuccessTuple:
186
196
  """
187
197
  Given a dictionary of options and the standard Meerschaum actions list,
188
198
  check if choice is valid and execute chosen function, else show available
@@ -247,7 +257,7 @@ def _get_subaction_names(action: str, globs: dict = None) -> List[str]:
247
257
  return subactions
248
258
 
249
259
 
250
- def choices_docstring(action: str, globs : Optional[Dict[str, Any]] = None) -> str:
260
+ def choices_docstring(action: str, globs: Optional[Dict[str, Any]] = None) -> str:
251
261
  """
252
262
  Append the an action's available options to the module docstring.
253
263
  This function is to be placed at the bottom of each action module.
@@ -155,10 +155,10 @@ def _complete_show_config(action: Optional[List[str]] = None, **kw : Any):
155
155
 
156
156
 
157
157
  def _show_pipes(
158
- nopretty: bool = False,
159
- debug: bool = False,
160
- **kw: Any
161
- ) -> SuccessTuple:
158
+ nopretty: bool = False,
159
+ debug: bool = False,
160
+ **kw: Any
161
+ ) -> SuccessTuple:
162
162
  """
163
163
  Print a stylized tree of available Meerschaum pipes.
164
164
  Respects global ANSI and UNICODE settings.
@@ -170,7 +170,7 @@ def _show_pipes(
170
170
  pipes = get_pipes(debug=debug, **kw)
171
171
 
172
172
  if len(pipes) == 0:
173
- return False, "No pipes to show."
173
+ return True, "No pipes to show."
174
174
 
175
175
  if len(flatten_pipes_dict(pipes)) == 1:
176
176
  return flatten_pipes_dict(pipes)[0].show(debug=debug, nopretty=nopretty, **kw)
@@ -7,7 +7,7 @@ Start subsystems (API server, logging daemon, etc.).
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.typing import SuccessTuple, Optional, List, Any
10
+ from meerschaum.utils.typing import SuccessTuple, Optional, List, Any, Union
11
11
 
12
12
  def start(
13
13
  action: Optional[List[str]] = None,
@@ -23,6 +23,7 @@ def start(
23
23
  'gui': _start_gui,
24
24
  'webterm': _start_webterm,
25
25
  'connectors': _start_connectors,
26
+ 'pipeline': _start_pipeline,
26
27
  }
27
28
  return choose_subaction(action, options, **kw)
28
29
 
@@ -537,6 +538,75 @@ def _complete_start_connectors(**kw) -> List[str]:
537
538
  return _complete_show_connectors(**kw)
538
539
 
539
540
 
541
+ def _start_pipeline(
542
+ action: Optional[List[str]] = None,
543
+ sub_args: Optional[List[str]] = None,
544
+ loop: bool = False,
545
+ min_seconds: Union[float, int, None] = 1.0,
546
+ params: Optional[Dict[str, Any]] = None,
547
+ **kwargs
548
+ ) -> SuccessTuple:
549
+ """
550
+ Run a series of Meerschaum commands as a single action.
551
+
552
+ Add `:` to the end of chained arguments to apply additional flags to the pipeline.
553
+
554
+ Examples
555
+ --------
556
+
557
+ `sync pipes -i sql:local + sync pipes -i sql:main :: -s 'daily'`
558
+
559
+ `show version + show arguments :: --loop`
560
+
561
+ """
562
+ import time
563
+ from meerschaum._internal.entry import entry
564
+ from meerschaum.utils.warnings import info, warn
565
+ from meerschaum.utils.misc import is_int
566
+
567
+ do_n_times = (
568
+ int(action[0].lstrip('x'))
569
+ if action and is_int(action[0].lstrip('x'))
570
+ else 1
571
+ )
572
+
573
+ if not sub_args:
574
+ return False, "Nothing to do."
575
+
576
+ if min_seconds is None:
577
+ min_seconds = 1.0
578
+
579
+ ran_n_times = 0
580
+ success, msg = False, "Did not run pipeline."
581
+ def run_loop():
582
+ nonlocal ran_n_times, success, msg
583
+ while True:
584
+ success, msg = entry(sub_args, _patch_args=params)
585
+ ran_n_times += 1
586
+
587
+ if not loop and do_n_times == 1:
588
+ break
589
+
590
+ if min_seconds != 0 and ran_n_times != do_n_times:
591
+ info(f"Sleeping for {min_seconds} seconds...")
592
+ time.sleep(min_seconds)
593
+
594
+ if loop:
595
+ continue
596
+
597
+ if ran_n_times >= do_n_times:
598
+ break
599
+
600
+ try:
601
+ run_loop()
602
+ except KeyboardInterrupt:
603
+ warn("Cancelled pipeline.", stack=False)
604
+
605
+ if do_n_times != 1:
606
+ info(f"Ran pipeline {ran_n_times} time" + ('s' if ran_n_times != 1 else '') + '.')
607
+ return success, msg
608
+
609
+
540
610
  ### NOTE: This must be the final statement of the module.
541
611
  ### Any subactions added below these lines will not
542
612
  ### be added to the `help` docstring.
@@ -18,7 +18,7 @@ from fastapi import WebSocket, WebSocketDisconnect
18
18
  from meerschaum.utils.misc import generate_password
19
19
  from meerschaum.jobs import Job
20
20
  from meerschaum.utils.warnings import warn
21
- from meerschaum.utils.typing import SuccessTuple, Union, List, Dict
21
+ from meerschaum.utils.typing import SuccessTuple, Union, List, Dict, Any
22
22
  from meerschaum.api import (
23
23
  fastapi, app, endpoints, get_api_connector, debug, manager, private, no_auth
24
24
  )
@@ -153,3 +153,50 @@ async def do_action_websocket(websocket: WebSocket):
153
153
  job.delete()
154
154
  _ = _temp_jobs.pop(job_name, None)
155
155
  stop_event.set()
156
+
157
+
158
+ @app.post(actions_endpoint + "/{action}", tags=['Actions'])
159
+ def do_action_legacy(
160
+ action: str,
161
+ keywords: Dict[str, Any] = fastapi.Body(...),
162
+ curr_user = (
163
+ fastapi.Depends(manager) if not no_auth else None
164
+ ),
165
+ ) -> SuccessTuple:
166
+ """
167
+ Perform a Meerschaum action (if permissions allow).
168
+
169
+ Parameters
170
+ ----------
171
+ action: str
172
+ The action to perform.
173
+
174
+ keywords: Dict[str, Any]
175
+ The keywords dictionary to pass to the action.
176
+
177
+ Returns
178
+ -------
179
+ A `SuccessTuple`.
180
+ """
181
+ if curr_user is not None and curr_user.type != 'admin':
182
+ from meerschaum.config import get_config
183
+ allow_non_admin = get_config(
184
+ 'system', 'api', 'permissions', 'actions', 'non_admin', patch=True
185
+ )
186
+ if not allow_non_admin:
187
+ return False, (
188
+ "The administrator for this server has not allowed users to perform actions.\n\n"
189
+ + "Please contact the system administrator, or if you are running this server, "
190
+ + "open the configuration file with `edit config system` "
191
+ + "and search for 'permissions'. "
192
+ + "\nUnder the keys 'api:permissions:actions', "
193
+ + "you can allow non-admin users to perform actions."
194
+ )
195
+
196
+ if action not in actions:
197
+ return False, f"Invalid action '{action}'."
198
+
199
+ keywords['mrsm_instance'] = keywords.get('mrsm_instance', str(get_api_connector()))
200
+ _debug = keywords.get('debug', debug)
201
+ keywords.pop('debug', None)
202
+ return actions[action](debug=_debug, **keywords)
@@ -185,6 +185,7 @@ paths = {
185
185
  'SYSTEMD_RESOURCES_PATH' : ('{DOT_CONFIG_DIR_PATH}', 'systemd'),
186
186
  'SYSTEMD_USER_RESOURCES_PATH' : ('{SYSTEMD_RESOURCES_PATH}', 'user'),
187
187
  'SYSTEMD_ROOT_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'systemd'),
188
+ 'SYSTEMD_JOBS_RESOURCES_PATH' : ('{SYSTEMD_ROOT_RESOURCES_PATH}', 'services'),
188
189
  'SYSTEMD_LOGS_RESOURCES_PATH' : ('{SYSTEMD_ROOT_RESOURCES_PATH}', 'logs'),
189
190
  }
190
191
 
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.3.0rc3"
5
+ __version__ = "2.3.1"
@@ -90,6 +90,8 @@ STATIC_CONFIG: Dict[str, Any] = {
90
90
  'failure_key': '_argparse_exception',
91
91
  'and_key': '+',
92
92
  'escaped_and_key': '++',
93
+ 'pipeline_key': ':',
94
+ 'escaped_pipeline_key': '::',
93
95
  },
94
96
  'urls': {
95
97
  'get-pip.py': 'https://bootstrap.pypa.io/get-pip.py',
@@ -377,5 +377,4 @@ def _load_builtin_custom_connectors():
377
377
  """
378
378
  Import custom connectors decorated with `@make_connector` or `@make_executor`.
379
379
  """
380
- import meerschaum.jobs._SystemdExecutor
381
- # import meerschaum.jobs._LocalExecutor
380
+ import meerschaum.jobs.systemd
@@ -33,7 +33,12 @@ class APIConnector(Connector):
33
33
  delete,
34
34
  wget,
35
35
  )
36
- from ._actions import get_actions, do_action, do_action_async
36
+ from ._actions import (
37
+ get_actions,
38
+ do_action,
39
+ do_action_async,
40
+ do_action_legacy,
41
+ )
37
42
  from ._misc import get_mrsm_version, get_chaining_status
38
43
  from ._pipes import (
39
44
  register_pipe,
@@ -13,7 +13,7 @@ import asyncio
13
13
  from functools import partial
14
14
 
15
15
  import meerschaum as mrsm
16
- from meerschaum.utils.typing import SuccessTuple, List, Callable
16
+ from meerschaum.utils.typing import SuccessTuple, List, Callable, Optional
17
17
  from meerschaum.config.static import STATIC_CONFIG
18
18
 
19
19
  ACTIONS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['actions']
@@ -74,3 +74,79 @@ async def do_action_async(
74
74
  break
75
75
 
76
76
  return True, "Success"
77
+
78
+
79
+ def do_action_legacy(
80
+ self,
81
+ action: Optional[List[str]] = None,
82
+ sysargs: Optional[List[str]] = None,
83
+ debug: bool = False,
84
+ **kw
85
+ ) -> SuccessTuple:
86
+ """
87
+ NOTE: This method is deprecated.
88
+ Please use `do_action()` or `do_action_async()`.
89
+
90
+ Execute a Meerschaum action remotely.
91
+
92
+ If `sysargs` are provided, parse those instead.
93
+ Otherwise infer everything from keyword arguments.
94
+
95
+ Examples
96
+ --------
97
+ >>> conn = mrsm.get_connector('api:main')
98
+ >>> conn.do_action(['show', 'pipes'])
99
+ (True, "Success")
100
+ >>> conn.do_action(['show', 'arguments'], name='test')
101
+ (True, "Success")
102
+ """
103
+ import sys, json
104
+ from meerschaum.utils.debug import dprint
105
+ from meerschaum.config.static import STATIC_CONFIG
106
+ from meerschaum.utils.misc import json_serialize_datetime
107
+ if action is None:
108
+ action = []
109
+
110
+ if sysargs is not None and action and action[0] == '':
111
+ from meerschaum._internal.arguments import parse_arguments
112
+ if debug:
113
+ dprint(f"Parsing sysargs:\n{sysargs}")
114
+ json_dict = parse_arguments(sysargs)
115
+ else:
116
+ json_dict = kw
117
+ json_dict['action'] = action
118
+ if 'noask' not in kw:
119
+ json_dict['noask'] = True
120
+ if 'yes' not in kw:
121
+ json_dict['yes'] = True
122
+ if debug:
123
+ json_dict['debug'] = debug
124
+
125
+ root_action = json_dict['action'][0]
126
+ del json_dict['action'][0]
127
+ r_url = f"{STATIC_CONFIG['api']['endpoints']['actions']}/{root_action}"
128
+
129
+ if debug:
130
+ from meerschaum.utils.formatting import pprint
131
+ dprint(f"Sending data to '{self.url + r_url}':")
132
+ pprint(json_dict, stream=sys.stderr)
133
+
134
+ response = self.post(
135
+ r_url,
136
+ data = json.dumps(json_dict, default=json_serialize_datetime),
137
+ debug = debug,
138
+ )
139
+ try:
140
+ response_list = json.loads(response.text)
141
+ if isinstance(response_list, dict) and 'detail' in response_list:
142
+ return False, response_list['detail']
143
+ except Exception as e:
144
+ print(f"Invalid response: {response}")
145
+ print(e)
146
+ return False, response.text
147
+ if debug:
148
+ dprint(response)
149
+ try:
150
+ return response_list[0], response_list[1]
151
+ except Exception as e:
152
+ return False, f"Failed to parse result from action '{root_action}'"