meerschaum 2.3.0.dev1__py3-none-any.whl → 2.3.0rc1__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 (56) hide show
  1. meerschaum/__init__.py +5 -2
  2. meerschaum/__main__.py +0 -5
  3. meerschaum/_internal/arguments/_parse_arguments.py +10 -3
  4. meerschaum/_internal/arguments/_parser.py +6 -2
  5. meerschaum/_internal/entry.py +36 -6
  6. meerschaum/_internal/shell/Shell.py +32 -20
  7. meerschaum/actions/__init__.py +8 -6
  8. meerschaum/actions/attach.py +31 -13
  9. meerschaum/actions/copy.py +68 -41
  10. meerschaum/actions/delete.py +64 -21
  11. meerschaum/actions/edit.py +3 -3
  12. meerschaum/actions/install.py +40 -32
  13. meerschaum/actions/pause.py +44 -27
  14. meerschaum/actions/restart.py +107 -0
  15. meerschaum/actions/show.py +8 -8
  16. meerschaum/actions/start.py +26 -41
  17. meerschaum/actions/stop.py +11 -4
  18. meerschaum/api/_events.py +10 -3
  19. meerschaum/api/dash/jobs.py +69 -70
  20. meerschaum/api/routes/_actions.py +8 -3
  21. meerschaum/api/routes/_jobs.py +86 -37
  22. meerschaum/config/_default.py +1 -1
  23. meerschaum/config/_paths.py +5 -0
  24. meerschaum/config/_shell.py +1 -1
  25. meerschaum/config/_version.py +1 -1
  26. meerschaum/config/static/__init__.py +6 -1
  27. meerschaum/connectors/Connector.py +13 -7
  28. meerschaum/connectors/__init__.py +21 -5
  29. meerschaum/connectors/api/APIConnector.py +3 -0
  30. meerschaum/connectors/api/_jobs.py +108 -11
  31. meerschaum/connectors/parse.py +10 -13
  32. meerschaum/core/Pipe/_bootstrap.py +16 -8
  33. meerschaum/jobs/_Executor.py +69 -0
  34. meerschaum/{utils/jobs → jobs}/_Job.py +206 -40
  35. meerschaum/jobs/_LocalExecutor.py +88 -0
  36. meerschaum/jobs/_SystemdExecutor.py +608 -0
  37. meerschaum/jobs/__init__.py +365 -0
  38. meerschaum/plugins/__init__.py +6 -6
  39. meerschaum/utils/daemon/Daemon.py +7 -0
  40. meerschaum/utils/daemon/RotatingFile.py +5 -2
  41. meerschaum/utils/daemon/StdinFile.py +12 -2
  42. meerschaum/utils/daemon/__init__.py +2 -0
  43. meerschaum/utils/formatting/_jobs.py +52 -16
  44. meerschaum/utils/misc.py +23 -5
  45. meerschaum/utils/packages/_packages.py +7 -4
  46. meerschaum/utils/process.py +9 -9
  47. meerschaum/utils/venv/__init__.py +2 -2
  48. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/METADATA +14 -17
  49. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/RECORD +55 -51
  50. meerschaum/utils/jobs/__init__.py +0 -245
  51. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/LICENSE +0 -0
  52. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/NOTICE +0 -0
  53. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/WHEEL +0 -0
  54. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/entry_points.txt +0 -0
  55. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/top_level.txt +0 -0
  56. {meerschaum-2.3.0.dev1.dist-info → meerschaum-2.3.0rc1.dist-info}/zip-safe +0 -0
meerschaum/__init__.py CHANGED
@@ -24,12 +24,13 @@ from meerschaum.utils.packages import attempt_import
24
24
  from meerschaum.core.Pipe import Pipe
25
25
  from meerschaum.plugins import Plugin
26
26
  from meerschaum.utils.venv import Venv
27
- from meerschaum.utils.jobs import Job
27
+ from meerschaum.jobs import Job, Executor, make_executor
28
28
  from meerschaum.connectors import get_connector, Connector, make_connector
29
29
  from meerschaum.utils import get_pipes
30
30
  from meerschaum.utils.formatting import pprint
31
31
  from meerschaum._internal.docs import index as __doc__
32
32
  from meerschaum.config import __version__, get_config
33
+ from meerschaum._internal.entry import entry
33
34
  from meerschaum.__main__ import _close_pools
34
35
 
35
36
  atexit.register(_close_pools)
@@ -44,7 +45,8 @@ __all__ = (
44
45
  "Venv",
45
46
  "Plugin",
46
47
  "Job",
47
- "Daemon",
48
+ "Executor",
49
+ "make_executor",
48
50
  "pprint",
49
51
  "attempt_import",
50
52
  "actions",
@@ -55,4 +57,5 @@ __all__ = (
55
57
  "SuccessTuple",
56
58
  "Connector",
57
59
  "make_connector",
60
+ "entry",
58
61
  )
meerschaum/__main__.py CHANGED
@@ -45,11 +45,6 @@ def main(sysargs: Optional[List[str]] = None) -> None:
45
45
  parse_version(sysargs)
46
46
  return _exit(old_cwd=old_cwd)
47
47
 
48
- if ('-d' in sysargs or '--daemon' in sysargs) and ('stack' not in sysargs):
49
- from meerschaum.utils.daemon import daemon_entry
50
- _print_tuple(daemon_entry(sysargs), upper_padding=1)
51
- return _exit(old_cwd=old_cwd)
52
-
53
48
  from meerschaum._internal.entry import entry, get_shell
54
49
 
55
50
  ### Try to launch a shell if --shell is provided.
@@ -288,9 +288,6 @@ def remove_leading_action(
288
288
  for a in action:
289
289
  _action.append(a.replace('_', UNDERSCORE_STANDIN))
290
290
 
291
- ### e.g. 'show_pipes_baz'
292
- action_str = '_'.join(_action)
293
-
294
291
  ### e.g. 'show_pipes'
295
292
  action_name = action_function.__name__.lstrip('_')
296
293
 
@@ -300,6 +297,16 @@ def remove_leading_action(
300
297
  ### Strip away any leading prefices.
301
298
  action_name = action_name[main_action_index:]
302
299
 
300
+ subaction_parts = action_name.replace(main_action_name, '').lstrip('_').split('_')
301
+ subaction_name = subaction_parts[0] if subaction_parts else None
302
+
303
+ ### e.g. 'pipe' -> 'pipes'
304
+ if subaction_name and subaction_name.endswith('s') and not action[1].endswith('s'):
305
+ _action[1] += 's'
306
+
307
+ ### e.g. 'show_pipes_baz'
308
+ action_str = '_'.join(_action)
309
+
303
310
  if not action_str.replace(UNDERSCORE_STANDIN, '_').startswith(action_name):
304
311
  warn(f"Unable to parse '{action_str}' for action '{action_name}'.")
305
312
  return action
@@ -66,7 +66,7 @@ def parse_executor_keys(executor_keys_str: str) -> Union[str, None]:
66
66
  """
67
67
  Ensure that only API keys are provided for executor_keys.
68
68
  """
69
- if executor_keys_str == 'local':
69
+ if executor_keys_str in ('local', 'systemd'):
70
70
  return executor_keys_str
71
71
 
72
72
  if executor_keys_str.lower() == 'none':
@@ -214,10 +214,14 @@ groups['jobs'].add_argument(
214
214
  '--restart', action='store_true',
215
215
  help=("Restart a job if not stopped manually."),
216
216
  )
217
+ groups['jobs'].add_argument(
218
+ '--systemd', action='store_true',
219
+ help=("Create a job via systemd. Shorthand for `-e systemd`."),
220
+ )
217
221
  groups['jobs'].add_argument(
218
222
  '--executor-keys', '--executor', '-e', type=parse_executor_keys,
219
223
  help=(
220
- "Remotely execute jobs on an API instance."
224
+ "Execute jobs on an API instance or via systemd."
221
225
  ),
222
226
  )
223
227
  groups['jobs'].add_argument(
@@ -8,7 +8,29 @@ The entry point for launching Meerschaum actions.
8
8
  """
9
9
 
10
10
  from __future__ import annotations
11
+
12
+ import os
13
+ import sys
11
14
  from meerschaum.utils.typing import SuccessTuple, List, Optional, Dict, Callable, Any
15
+ from meerschaum.config.static import STATIC_CONFIG as _STATIC_CONFIG
16
+
17
+ _systemd_result_path = None
18
+ if (_STATIC_CONFIG['environment']['systemd_log_path']) in os.environ:
19
+ from meerschaum.utils.daemon import RotatingFile as _RotatingFile, StdinFile as _StdinFile
20
+ from meerschaum.config import get_config as _get_config
21
+
22
+ _systemd_result_path = os.environ[_STATIC_CONFIG['environment']['systemd_result_path']]
23
+ _systemd_log_path = os.environ[_STATIC_CONFIG['environment']['systemd_log_path']]
24
+ _systemd_log = _RotatingFile(
25
+ _systemd_log_path,
26
+ write_timestamps=True,
27
+ timestamp_format=_get_config('jobs', 'logs', 'timestamps', 'format'),
28
+ )
29
+ sys.stdout = _systemd_log
30
+ sys.stderr = _systemd_log
31
+ _systemd_stdin_path = os.environ.get(_STATIC_CONFIG['environment']['systemd_stdin_path'], None)
32
+ if _systemd_stdin_path:
33
+ sys.stdin = _StdinFile(_systemd_stdin_path)
12
34
 
13
35
  def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
14
36
  """
@@ -87,6 +109,10 @@ def entry_with_args(
87
109
  kw['action'].insert(1, api_label)
88
110
  skip_schedule = True
89
111
 
112
+ ### If the `--daemon` flag is present, prepend 'start job'.
113
+ if kw.get('daemon', False) and kw['action'][0] != 'stack':
114
+ kw['action'] = ['start', 'jobs'] + kw['action']
115
+
90
116
  action_function = get_action(kw['action'], _actions=_actions)
91
117
 
92
118
  ### If action does not exist, execute in a subshell.
@@ -117,7 +143,6 @@ def entry_with_args(
117
143
  **kw
118
144
  )
119
145
 
120
-
121
146
  if kw.get('schedule', None) and not skip_schedule:
122
147
  from meerschaum.utils.schedule import schedule_function
123
148
  from meerschaum.utils.misc import interval_str
@@ -134,6 +159,11 @@ def entry_with_args(
134
159
  for venv in [venv for venv in active_venvs]:
135
160
  deactivate_venv(venv, debug=kw.get('debug', False), force=True)
136
161
 
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
+
137
167
  return result
138
168
 
139
169
 
@@ -160,16 +190,16 @@ def _do_action_wrapper(action_function, plugin_name, **kw):
160
190
  )
161
191
  )
162
192
  except KeyboardInterrupt:
163
- result = False, f"Cancelled action `{action_name}`."
193
+ result = False, f"Cancelled action `{action_name.lstrip()}`."
164
194
  return result
165
195
 
166
196
  _shells = []
167
197
  _shell = None
168
198
  def get_shell(
169
- sysargs: Optional[List[str]] = None,
170
- reload: bool = False,
171
- debug: bool = False
172
- ):
199
+ sysargs: Optional[List[str]] = None,
200
+ reload: bool = False,
201
+ debug: bool = False
202
+ ):
173
203
  """Initialize and return the Meerschaum shell object."""
174
204
  global _shell
175
205
  from meerschaum.utils.debug import dprint
@@ -29,6 +29,7 @@ from meerschaum._internal.shell.ValidAutoSuggest import ValidAutoSuggest
29
29
  from meerschaum._internal.shell.ShellCompleter import ShellCompleter
30
30
  _clear_screen = get_config('shell', 'clear_screen', patch=True)
31
31
  from meerschaum.utils.misc import string_width, remove_ansi
32
+ from meerschaum.jobs import get_executor_keys_from_context
32
33
 
33
34
  patch = True
34
35
  ### remove default cmd2 commands
@@ -339,10 +340,7 @@ class Shell(cmd.Cmd):
339
340
  if shell_attrs.get('repo_keys', None) is None:
340
341
  shell_attrs['repo_keys'] = get_config('meerschaum', 'default_repository', patch=patch)
341
342
  if shell_attrs.get('executor_keys', None) is None:
342
- shell_attrs['executor_keys'] = get_config(
343
- 'meerschaum', 'default_executor',
344
- patch=patch,
345
- ) or 'local'
343
+ shell_attrs['executor_keys'] = get_executor_keys_from_context()
346
344
 
347
345
  ### this will be updated later in update_prompt ONLY IF {username} is in the prompt
348
346
  shell_attrs['username'] = ''
@@ -564,11 +562,6 @@ class Shell(cmd.Cmd):
564
562
  self.emptyline()
565
563
  return ""
566
564
 
567
- ### If the `--daemon` flag is present, prepend 'start job'.
568
- if args.get('daemon', False) and 'stack' not in args['action']:
569
- args['action'] = ['start', 'jobs'] + args['action']
570
- main_action_name = 'start'
571
-
572
565
  positional_only = (main_action_name not in shell_attrs['_actions'])
573
566
  if positional_only:
574
567
  return original_line
@@ -577,7 +570,6 @@ class Shell(cmd.Cmd):
577
570
 
578
571
  try:
579
572
  success_tuple = entry_with_args(_actions=shell_attrs['_actions'], **args)
580
- # success_tuple = entry_with_args(**args)
581
573
  except Exception as e:
582
574
  success_tuple = False, str(e)
583
575
 
@@ -585,9 +577,9 @@ class Shell(cmd.Cmd):
585
577
  if isinstance(success_tuple, tuple):
586
578
  print_tuple(
587
579
  success_tuple,
588
- skip_common = (not shell_attrs['debug']),
589
- upper_padding = 1,
590
- lower_padding = 0,
580
+ skip_common=(not shell_attrs['debug']),
581
+ upper_padding=1,
582
+ lower_padding=0,
591
583
  )
592
584
 
593
585
  ### Restore the old working directory.
@@ -700,14 +692,33 @@ class Shell(cmd.Cmd):
700
692
  return True, "Success"
701
693
 
702
694
 
703
- def complete_instance(self, text: str, line: str, begin_index: int, end_index: int):
695
+ def complete_instance(
696
+ self,
697
+ text: str,
698
+ line: str,
699
+ begin_index: int,
700
+ end_index: int,
701
+ _executor: bool = False,
702
+ _additional_options: Optional[List[str]] = None,
703
+ ):
704
704
  from meerschaum.utils.misc import get_connector_labels
705
705
  from meerschaum._internal.arguments._parse_arguments import parse_line
706
- from meerschaum.connectors import instance_types
706
+ from meerschaum.connectors import instance_types, _load_builtin_custom_connectors
707
+ if _executor:
708
+ _load_builtin_custom_connectors()
709
+ from meerschaum.jobs import executor_types
710
+
711
+ conn_types = instance_types if not _executor else executor_types
712
+
707
713
  args = parse_line(line)
708
714
  action = args['action']
709
715
  _text = action[1] if len(action) > 1 else ""
710
- return get_connector_labels(*instance_types, search_term=_text, ignore_exact_match=True)
716
+ return get_connector_labels(
717
+ *conn_types,
718
+ search_term=_text,
719
+ ignore_exact_match=True,
720
+ _additional_options=_additional_options,
721
+ )
711
722
 
712
723
 
713
724
  def do_repo(
@@ -802,18 +813,19 @@ class Shell(cmd.Cmd):
802
813
  except (IndexError, AttributeError):
803
814
  executor_keys = ''
804
815
  if executor_keys == '':
805
- executor_keys = get_config('meerschaum', 'default_executor') or 'local'
816
+ executor_keys = get_executor_keys_from_context()
806
817
 
807
818
  conn = parse_executor_keys(executor_keys, debug=debug)
808
819
 
809
- shell_attrs['executor_keys'] = str(conn)
820
+ shell_attrs['executor_keys'] = str(conn).replace('systemd:main', 'systemd')
810
821
 
811
822
  info(f"Default executor for the current shell: {executor_keys}")
812
823
  return True, "Success"
813
824
 
814
825
  def complete_executor(self, *args) -> List[str]:
815
- results = self.complete_instance(*args)
816
- return ['local'] + [result for result in results if result.startswith('api:')]
826
+ from meerschaum.jobs import executor_types
827
+ results = self.complete_instance(*args, _executor=True, _additional_options=['local'])
828
+ return [result for result in results if result.split(':')[0] in executor_types]
817
829
 
818
830
  def do_help(self, line: str, executor_keys=None) -> List[str]:
819
831
  """
@@ -12,9 +12,9 @@ from meerschaum.utils.packages import get_modules_from_package
12
12
  _custom_actions = []
13
13
 
14
14
  def get_subactions(
15
- action: Union[str, List[str]],
16
- _actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
17
- ) -> Dict[str, Callable[[Any], Any]]:
15
+ action: Union[str, List[str]],
16
+ _actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
17
+ ) -> Dict[str, Callable[[Any], Any]]:
18
18
  """
19
19
  Return a dictionary of an action's sub-action functions.
20
20
 
@@ -52,9 +52,9 @@ def get_subactions(
52
52
 
53
53
 
54
54
  def get_action(
55
- action: Union[str, List[str]],
56
- _actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
57
- ) -> Union[Callable[[Any], Any], None]:
55
+ action: Union[str, List[str]],
56
+ _actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
57
+ ) -> Union[Callable[[Any], Any], None]:
58
58
  """
59
59
  Return a function corresponding to the given action list.
60
60
  This may be a custom action with an underscore, in which case, allow for underscores.
@@ -92,6 +92,8 @@ def get_action(
92
92
  if action[0] in _actions:
93
93
  subactions = get_subactions([action[0]], _actions=_actions)
94
94
  if action[1] not in subactions:
95
+ if (action[1] + 's') in subactions:
96
+ return subactions[action[1] + 's']
95
97
  return _actions[action[0]]
96
98
  return subactions[action[1]]
97
99
 
@@ -11,17 +11,18 @@ from meerschaum.utils.typing import Optional, List, Any, SuccessTuple
11
11
 
12
12
  def attach(
13
13
  action: Optional[List[str]] = None,
14
+ executor_keys: Optional[str] = None,
14
15
  **kwargs: Any
15
16
  ) -> SuccessTuple:
16
17
  """
17
- Attach to a job.
18
+ Attach to a job, and prompt the user when blocking on input.
18
19
  """
19
20
  from meerschaum.actions import choose_subaction
20
21
  attach_options = {
21
22
  'jobs': _attach_jobs,
22
23
  'logs': _attach_logs,
23
24
  }
24
- return choose_subaction(action, attach_options, **kwargs)
25
+ return choose_subaction(action, attach_options, executor_keys=executor_keys, **kwargs)
25
26
 
26
27
 
27
28
  def _complete_attach(
@@ -31,16 +32,16 @@ def _complete_attach(
31
32
  """
32
33
  Override the default Meerschaum `complete_` function.
33
34
  """
34
- from meerschaum.actions.start import _complete_start_jobs
35
+ from meerschaum.actions.delete import _complete_delete_jobs
35
36
 
36
37
  if action is None:
37
38
  action = []
38
39
 
39
40
  options = {
40
- 'job': _complete_start_jobs,
41
- 'jobs': _complete_start_jobs,
42
- 'log': _complete_start_jobs,
43
- 'logs': _complete_start_jobs,
41
+ 'job': _complete_delete_jobs,
42
+ 'jobs': _complete_delete_jobs,
43
+ 'log': _complete_delete_jobs,
44
+ 'logs': _complete_delete_jobs,
44
45
  }
45
46
 
46
47
  if (
@@ -64,20 +65,37 @@ def _attach_jobs(
64
65
  """
65
66
  Attach to a job, and prompt the user when blocking on input.
66
67
  """
68
+ action = action or []
67
69
  if not action and not name:
68
70
  return False, "Provide the name of the job to attach to."
69
71
 
70
72
  name = name or action[0]
71
73
  job = mrsm.Job(name, executor_keys=executor_keys)
74
+ other_executor_keys = 'systemd' if executor_keys in (None, 'local') else 'local'
72
75
  if not job.exists():
73
- return False, f"Job '{job.name}' does not exist."
76
+ other_job = mrsm.Job(name, executor_keys=other_executor_keys)
77
+ if not other_job.exists():
78
+ return False, f"Job '{job.name}' does not exist."
79
+
80
+ job = other_job
81
+
82
+ success, message = True, "Success"
83
+
84
+ def _capture_result(result: SuccessTuple):
85
+ nonlocal success, message
86
+ success, message = result
74
87
 
75
- job.monitor_logs(
76
- stop_on_exit=True,
77
- strip_timestamps=True,
78
- )
88
+ try:
89
+ job.monitor_logs(
90
+ stop_callback_function=_capture_result,
91
+ accept_input=True,
92
+ stop_on_exit=True,
93
+ strip_timestamps=True,
94
+ )
95
+ except KeyboardInterrupt:
96
+ pass
79
97
 
80
- return True, "Success"
98
+ return success, message
81
99
 
82
100
 
83
101
  def _attach_logs(*args, **kwargs) -> SuccessTuple:
@@ -10,9 +10,9 @@ from __future__ import annotations
10
10
  from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
11
11
 
12
12
  def copy(
13
- action: Optional[List[str]] = None,
14
- **kw : Any
15
- ) -> SuccessTuple:
13
+ action: Optional[List[str]] = None,
14
+ **kw : Any
15
+ ) -> SuccessTuple:
16
16
  """
17
17
  Duplicate connectors or pipes.
18
18
 
@@ -32,17 +32,16 @@ def copy(
32
32
 
33
33
 
34
34
  def _complete_copy(
35
- action : Optional[List[str]] = None,
36
- **kw : Any
37
- ) -> List[str]:
35
+ action: Optional[List[str]] = None,
36
+ **kw: Any
37
+ ) -> List[str]:
38
38
  """
39
39
  Override the default Meerschaum `complete_` function.
40
-
41
40
  """
42
- from meerschaum.actions.start import _complete_start_jobs
43
41
  from meerschaum.actions.edit import _complete_edit_config
44
42
  if action is None:
45
43
  action = []
44
+
46
45
  options = {
47
46
  'connector': _complete_copy_connectors,
48
47
  'connectors': _complete_copy_connectors,
@@ -61,15 +60,14 @@ def _complete_copy(
61
60
 
62
61
 
63
62
  def _copy_pipes(
64
- yes: bool = False,
65
- noask: bool = False,
66
- force: bool = False,
67
- debug: bool = False,
68
- **kw
69
- ) -> SuccessTuple:
63
+ yes: bool = False,
64
+ noask: bool = False,
65
+ force: bool = False,
66
+ debug: bool = False,
67
+ **kw
68
+ ) -> SuccessTuple:
70
69
  """
71
70
  Copy pipes' attributes and make new pipes.
72
-
73
71
  """
74
72
  from meerschaum import get_pipes, Pipe
75
73
  from meerschaum.utils.prompt import prompt, yes_no
@@ -132,16 +130,15 @@ def _copy_pipes(
132
130
 
133
131
  return successes > 0, msg
134
132
 
133
+
135
134
  def _copy_connectors(
136
- action: Optional[List[str]] = None,
137
- connector_keys: Optional[List[str]] = None,
138
- nopretty: bool = False,
139
- yes: bool = False,
140
- force: bool = False,
141
- noask: bool = False,
142
- debug: bool = False,
143
- **kw
144
- ) -> SuccessTuple:
135
+ action: Optional[List[str]] = None,
136
+ connector_keys: Optional[List[str]] = None,
137
+ nopretty: bool = False,
138
+ force: bool = False,
139
+ debug: bool = False,
140
+ **kwargs: Any
141
+ ) -> SuccessTuple:
145
142
  """
146
143
  Create a new connector from an existing one.
147
144
 
@@ -153,39 +150,69 @@ def _copy_connectors(
153
150
  from meerschaum.config._edit import write_config
154
151
  from meerschaum.utils.warnings import info, warn
155
152
  from meerschaum.utils.formatting import pprint
153
+ from meerschaum.actions import get_action
156
154
  cf = _config()
157
155
  if action is None:
158
156
  action = []
159
157
  if connector_keys is None:
160
158
  connector_keys = []
161
159
 
162
- _keys = list(set(action + connector_keys))
160
+ _keys = (action or []) + connector_keys
163
161
 
164
162
  if not _keys:
165
163
  return False, "No connectors to copy."
166
164
 
167
- for ck in _keys:
168
- try:
169
- conn = parse_connector_keys(ck)
170
- except Exception as e:
171
- warn(f"Unable to parse connector '{ck}'. Skipping...", stack=False)
172
- continue
165
+ if len(_keys) < 1 or len(_keys) > 2:
166
+ return False, "Provide one set of connector keys."
173
167
 
174
- attrs = get_config('meerschaum', 'connectors', conn.type, conn.label)
175
- pprint(attrs, nopretty=nopretty)
168
+ ck = _keys[0]
176
169
 
177
- asking = True
178
- # while asking:
179
- # new_ck = prompt("Please enter a new label for the new connector ():")
170
+ try:
171
+ conn = parse_connector_keys(ck)
172
+ except Exception as e:
173
+ return False, f"Unable to parse connector '{ck}'."
180
174
 
175
+ if len(_keys) == 2:
176
+ new_ck = _keys[1] if ':' in _keys[1] else None
177
+ new_label = _keys[1].split(':')[-1]
178
+ else:
179
+ new_ck = None
180
+ new_label = None
181
+
182
+ try:
183
+ if new_label is None:
184
+ new_label = prompt(f"Enter a label for the new '{conn.type}' connector:")
185
+ except KeyboardInterrupt:
186
+ return False, "Nothing was copied."
187
+
188
+ if new_ck is None:
189
+ new_ck = f"{conn.type}:{new_label}"
190
+
191
+ info(f"Registering connector '{new_ck}' from '{ck}'...")
192
+
193
+ attrs = get_config('meerschaum', 'connectors', conn.type, conn.label)
194
+ pprint(attrs, nopretty=nopretty)
195
+ if not force and not yes_no(
196
+ f"Register connector '{new_ck}' with the above attributes?",
197
+ default='n',
198
+ **kwargs
199
+ ):
200
+ return False, "Nothing was copied."
201
+
202
+ register_connector = get_action(['register', 'connector'])
203
+ register_success, register_msg = register_connector(
204
+ [new_ck],
205
+ params=attrs,
206
+ **kwargs
207
+ )
208
+ return register_success, register_msg
181
209
 
182
- return False, "Not implemented."
183
210
 
184
211
  def _complete_copy_connectors(
185
- action : Optional[List[str]] = None,
186
- line : str = '',
187
- **kw : Any
188
- ) -> List[str]:
212
+ action: Optional[List[str]] = None,
213
+ line: str = '',
214
+ **kw: Any
215
+ ) -> List[str]:
189
216
  from meerschaum.config import get_config
190
217
  from meerschaum.utils.misc import get_connector_labels
191
218
  types = list(get_config('meerschaum', 'connectors').keys())