meerschaum 2.2.6__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerschaum/__init__.py +6 -1
- meerschaum/__main__.py +9 -9
- meerschaum/_internal/arguments/__init__.py +1 -1
- meerschaum/_internal/arguments/_parse_arguments.py +72 -6
- meerschaum/_internal/arguments/_parser.py +45 -15
- meerschaum/_internal/docs/index.py +265 -8
- meerschaum/_internal/entry.py +167 -37
- meerschaum/_internal/shell/Shell.py +290 -99
- meerschaum/_internal/shell/updates.py +175 -0
- meerschaum/actions/__init__.py +29 -17
- meerschaum/actions/api.py +12 -12
- meerschaum/actions/attach.py +113 -0
- meerschaum/actions/copy.py +68 -41
- meerschaum/actions/delete.py +112 -50
- meerschaum/actions/edit.py +3 -3
- meerschaum/actions/install.py +40 -32
- meerschaum/actions/pause.py +44 -27
- meerschaum/actions/register.py +19 -5
- meerschaum/actions/restart.py +107 -0
- meerschaum/actions/show.py +130 -159
- meerschaum/actions/start.py +161 -100
- meerschaum/actions/stop.py +78 -42
- meerschaum/actions/sync.py +3 -3
- meerschaum/actions/upgrade.py +28 -36
- meerschaum/api/_events.py +25 -1
- meerschaum/api/_oauth2.py +2 -0
- meerschaum/api/_websockets.py +2 -2
- meerschaum/api/dash/callbacks/jobs.py +36 -44
- meerschaum/api/dash/jobs.py +89 -78
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +148 -17
- meerschaum/api/routes/_jobs.py +407 -0
- meerschaum/api/routes/_pipes.py +25 -25
- meerschaum/config/_default.py +1 -0
- meerschaum/config/_formatting.py +1 -0
- meerschaum/config/_jobs.py +1 -1
- meerschaum/config/_paths.py +11 -0
- meerschaum/config/_shell.py +84 -67
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +18 -0
- meerschaum/connectors/Connector.py +13 -7
- meerschaum/connectors/__init__.py +28 -15
- meerschaum/connectors/api/APIConnector.py +27 -1
- meerschaum/connectors/api/_actions.py +71 -6
- meerschaum/connectors/api/_jobs.py +368 -0
- meerschaum/connectors/api/_misc.py +1 -1
- meerschaum/connectors/api/_pipes.py +85 -84
- meerschaum/connectors/api/_request.py +13 -9
- meerschaum/connectors/parse.py +27 -15
- meerschaum/core/Pipe/_bootstrap.py +16 -8
- meerschaum/core/Pipe/_sync.py +3 -0
- meerschaum/jobs/_Executor.py +69 -0
- meerschaum/jobs/_Job.py +899 -0
- meerschaum/jobs/__init__.py +396 -0
- meerschaum/jobs/systemd.py +694 -0
- meerschaum/plugins/__init__.py +97 -12
- meerschaum/utils/daemon/Daemon.py +352 -147
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +19 -10
- meerschaum/utils/daemon/RotatingFile.py +22 -8
- meerschaum/utils/daemon/StdinFile.py +121 -0
- meerschaum/utils/daemon/__init__.py +42 -27
- meerschaum/utils/daemon/_names.py +15 -13
- meerschaum/utils/formatting/__init__.py +83 -37
- meerschaum/utils/formatting/_jobs.py +146 -55
- meerschaum/utils/formatting/_shell.py +6 -0
- meerschaum/utils/misc.py +41 -22
- meerschaum/utils/packages/__init__.py +21 -15
- meerschaum/utils/packages/_packages.py +9 -6
- meerschaum/utils/process.py +9 -9
- meerschaum/utils/prompt.py +20 -7
- meerschaum/utils/schedule.py +21 -15
- meerschaum/utils/venv/__init__.py +2 -2
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/METADATA +22 -25
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/RECORD +80 -70
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/WHEEL +1 -1
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dist-info}/zip-safe +0 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
If configured, check `api:mrsm` for announcement messages.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import json
|
10
|
+
from datetime import datetime, timezone, timedelta
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
from meerschaum.utils.typing import Union, SuccessTuple, Optional
|
14
|
+
from meerschaum.config import get_config
|
15
|
+
from meerschaum.utils.formatting import CHARSET, ANSI, colored
|
16
|
+
from meerschaum.utils.misc import string_width, remove_ansi
|
17
|
+
from meerschaum.config.paths import (
|
18
|
+
UPDATES_LOCK_PATH,
|
19
|
+
UPDATES_CACHE_PATH,
|
20
|
+
)
|
21
|
+
from meerschaum.utils.threading import Thread
|
22
|
+
|
23
|
+
|
24
|
+
def cache_remote_version(debug: bool = False) -> SuccessTuple:
|
25
|
+
"""
|
26
|
+
Fetch and cache the latest version if available.
|
27
|
+
"""
|
28
|
+
allow_update_check = get_config('shell', 'updates', 'check_remote')
|
29
|
+
if not allow_update_check:
|
30
|
+
return True, "Update checks are disabled."
|
31
|
+
|
32
|
+
refresh_minutes = get_config('shell', 'updates', 'refresh_minutes')
|
33
|
+
update_delta = timedelta(minutes=refresh_minutes)
|
34
|
+
|
35
|
+
if UPDATES_CACHE_PATH.exists():
|
36
|
+
try:
|
37
|
+
with open(UPDATES_CACHE_PATH, 'r', encoding='utf8') as f:
|
38
|
+
cache_dict = json.load(f)
|
39
|
+
except Exception:
|
40
|
+
cache_dict = {}
|
41
|
+
else:
|
42
|
+
cache_dict = {}
|
43
|
+
|
44
|
+
now = datetime.now(timezone.utc)
|
45
|
+
last_check_ts_str = cache_dict.get('last_check_ts')
|
46
|
+
last_check_ts = datetime.fromisoformat(last_check_ts_str) if last_check_ts_str else None
|
47
|
+
|
48
|
+
need_update = (
|
49
|
+
last_check_ts_str is None
|
50
|
+
or ((now - last_check_ts) >= update_delta)
|
51
|
+
)
|
52
|
+
|
53
|
+
if not need_update:
|
54
|
+
return True, "No updates are needed."
|
55
|
+
|
56
|
+
try:
|
57
|
+
conn = mrsm.get_connector('api:mrsm')
|
58
|
+
remote_version = conn.get_mrsm_version(debug=debug, timeout=3)
|
59
|
+
except Exception:
|
60
|
+
remote_version = None
|
61
|
+
|
62
|
+
if remote_version is None:
|
63
|
+
return False, "Could not determine remote version."
|
64
|
+
|
65
|
+
with open(UPDATES_CACHE_PATH, 'w+', encoding='utf-8') as f:
|
66
|
+
json.dump(
|
67
|
+
{
|
68
|
+
'last_check_ts': now.isoformat(),
|
69
|
+
'remote_version': remote_version,
|
70
|
+
},
|
71
|
+
f,
|
72
|
+
)
|
73
|
+
|
74
|
+
return True, "Updated remote version cache."
|
75
|
+
|
76
|
+
|
77
|
+
def run_version_check_thread(debug: bool = False) -> Union[Thread, None]:
|
78
|
+
"""
|
79
|
+
Run the version update check in a separate thread.
|
80
|
+
"""
|
81
|
+
allow_update_check = get_config('shell', 'updates', 'check_remote')
|
82
|
+
if not allow_update_check:
|
83
|
+
return None
|
84
|
+
|
85
|
+
thread = Thread(
|
86
|
+
target=cache_remote_version,
|
87
|
+
daemon=True,
|
88
|
+
kwargs={'debug': debug},
|
89
|
+
)
|
90
|
+
thread.start()
|
91
|
+
return thread
|
92
|
+
|
93
|
+
|
94
|
+
_remote_version: Optional[str] = None
|
95
|
+
def get_remote_version_from_cache() -> Optional[str]:
|
96
|
+
"""
|
97
|
+
Return the version string from the local cache file.
|
98
|
+
"""
|
99
|
+
global _remote_version
|
100
|
+
try:
|
101
|
+
with open(UPDATES_CACHE_PATH, 'r', encoding='utf-8') as f:
|
102
|
+
cache_dict = json.load(f)
|
103
|
+
except Exception:
|
104
|
+
return None
|
105
|
+
|
106
|
+
_remote_version = cache_dict.get('remote_version')
|
107
|
+
return _remote_version
|
108
|
+
|
109
|
+
|
110
|
+
_out_of_date: Optional[bool] = None
|
111
|
+
def mrsm_out_of_date() -> bool:
|
112
|
+
"""
|
113
|
+
Determine whether to print the upgrade message.
|
114
|
+
"""
|
115
|
+
global _out_of_date
|
116
|
+
if _out_of_date is not None:
|
117
|
+
return _out_of_date
|
118
|
+
|
119
|
+
### NOTE: Remote version is cached asynchronously.
|
120
|
+
if not UPDATES_CACHE_PATH.exists():
|
121
|
+
return False
|
122
|
+
|
123
|
+
remote_version_str = get_remote_version_from_cache()
|
124
|
+
|
125
|
+
packaging_version = mrsm.attempt_import('packaging.version')
|
126
|
+
current_version = packaging_version.parse(mrsm.__version__)
|
127
|
+
remote_version = packaging_version.parse(remote_version_str)
|
128
|
+
|
129
|
+
_out_of_date = remote_version > current_version
|
130
|
+
return _out_of_date
|
131
|
+
|
132
|
+
|
133
|
+
def get_update_message() -> str:
|
134
|
+
"""
|
135
|
+
Return the formatted message for when the current version is behind the latest release.
|
136
|
+
"""
|
137
|
+
if not mrsm_out_of_date():
|
138
|
+
return ''
|
139
|
+
|
140
|
+
intro = get_config('shell', CHARSET, 'intro')
|
141
|
+
update_message = get_config('shell', CHARSET, 'update_message')
|
142
|
+
remote_version = get_remote_version_from_cache()
|
143
|
+
if not remote_version:
|
144
|
+
return ''
|
145
|
+
|
146
|
+
intro_width = string_width(intro)
|
147
|
+
msg_width = string_width(update_message)
|
148
|
+
update_left_padding = ' ' * ((intro_width - msg_width) // 2)
|
149
|
+
|
150
|
+
update_line = (
|
151
|
+
colored(
|
152
|
+
update_message,
|
153
|
+
*get_config('shell', 'ansi', 'update_message', 'color')
|
154
|
+
) if ANSI
|
155
|
+
else update_message
|
156
|
+
)
|
157
|
+
update_instruction = (
|
158
|
+
colored("Run ", 'white')
|
159
|
+
+ colored("upgrade mrsm", 'green')
|
160
|
+
+ colored(" to install ", 'white')
|
161
|
+
+ colored(f'v{remote_version}', 'yellow')
|
162
|
+
+ '.'
|
163
|
+
)
|
164
|
+
update_instruction_clean = remove_ansi(update_instruction)
|
165
|
+
instruction_width = string_width(update_instruction_clean)
|
166
|
+
instruction_left_padding = ' ' * ((intro_width - instruction_width) // 2)
|
167
|
+
|
168
|
+
return (
|
169
|
+
'\n\n'
|
170
|
+
+ update_left_padding
|
171
|
+
+ update_line
|
172
|
+
+ '\n'
|
173
|
+
+ instruction_left_padding
|
174
|
+
+ update_instruction
|
175
|
+
)
|
meerschaum/actions/__init__.py
CHANGED
@@ -11,10 +11,20 @@ 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
|
-
|
16
|
-
|
17
|
-
|
25
|
+
action: Union[str, List[str]],
|
26
|
+
_actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
|
27
|
+
) -> Dict[str, Callable[[Any], Any]]:
|
18
28
|
"""
|
19
29
|
Return a dictionary of an action's sub-action functions.
|
20
30
|
|
@@ -52,9 +62,9 @@ def get_subactions(
|
|
52
62
|
|
53
63
|
|
54
64
|
def get_action(
|
55
|
-
|
56
|
-
|
57
|
-
|
65
|
+
action: Union[str, List[str]],
|
66
|
+
_actions: Optional[Dict[str, Callable[[Any], Any]]] = None,
|
67
|
+
) -> Union[Callable[[Any], Any], None]:
|
58
68
|
"""
|
59
69
|
Return a function corresponding to the given action list.
|
60
70
|
This may be a custom action with an underscore, in which case, allow for underscores.
|
@@ -92,6 +102,8 @@ def get_action(
|
|
92
102
|
if action[0] in _actions:
|
93
103
|
subactions = get_subactions([action[0]], _actions=_actions)
|
94
104
|
if action[1] not in subactions:
|
105
|
+
if (action[1] + 's') in subactions:
|
106
|
+
return subactions[action[1] + 's']
|
95
107
|
return _actions[action[0]]
|
96
108
|
return subactions[action[1]]
|
97
109
|
|
@@ -99,9 +111,9 @@ def get_action(
|
|
99
111
|
|
100
112
|
|
101
113
|
def get_main_action_name(
|
102
|
-
|
103
|
-
|
104
|
-
|
114
|
+
action: Union[List[str], str],
|
115
|
+
_actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
|
116
|
+
) -> Union[str, None]:
|
105
117
|
"""
|
106
118
|
Given an action list, return the name of the main function.
|
107
119
|
For subactions, this will return the root function.
|
@@ -138,9 +150,9 @@ def get_main_action_name(
|
|
138
150
|
|
139
151
|
|
140
152
|
def get_completer(
|
141
|
-
|
142
|
-
|
143
|
-
|
153
|
+
action: Union[List[str], str],
|
154
|
+
_actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
|
155
|
+
) -> Union[
|
144
156
|
Callable[['meerschaum._internal.shell.Shell', str, str, int, int], List[str]], None
|
145
157
|
]:
|
146
158
|
"""Search for a custom completer function for an action."""
|
@@ -177,10 +189,10 @@ def get_completer(
|
|
177
189
|
|
178
190
|
|
179
191
|
def choose_subaction(
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
192
|
+
action: Optional[List[str]] = None,
|
193
|
+
options: Optional[Dict[str, Any]] = None,
|
194
|
+
**kw
|
195
|
+
) -> SuccessTuple:
|
184
196
|
"""
|
185
197
|
Given a dictionary of options and the standard Meerschaum actions list,
|
186
198
|
check if choice is valid and execute chosen function, else show available
|
@@ -245,7 +257,7 @@ def _get_subaction_names(action: str, globs: dict = None) -> List[str]:
|
|
245
257
|
return subactions
|
246
258
|
|
247
259
|
|
248
|
-
def choices_docstring(action: str, globs
|
260
|
+
def choices_docstring(action: str, globs: Optional[Dict[str, Any]] = None) -> str:
|
249
261
|
"""
|
250
262
|
Append the an action's available options to the module docstring.
|
251
263
|
This function is to be placed at the bottom of each action module.
|
meerschaum/actions/api.py
CHANGED
@@ -10,12 +10,12 @@ import os
|
|
10
10
|
from meerschaum.utils.typing import SuccessTuple, Optional, List, Any
|
11
11
|
|
12
12
|
def api(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
action: Optional[List[str]] = None,
|
14
|
+
sysargs: Optional[List[str]] = None,
|
15
|
+
debug: bool = False,
|
16
|
+
mrsm_instance: Optional[str] = None,
|
17
|
+
**kw: Any
|
18
|
+
) -> SuccessTuple:
|
19
19
|
"""
|
20
20
|
Send commands to a Meerschaum WebAPI instance.
|
21
21
|
|
@@ -37,7 +37,8 @@ def api(
|
|
37
37
|
"""
|
38
38
|
from meerschaum.utils.warnings import warn, info
|
39
39
|
from meerschaum.utils.formatting import print_tuple
|
40
|
-
from meerschaum.
|
40
|
+
from meerschaum._internal.arguments._parse_arguments import parse_dict_to_sysargs
|
41
|
+
|
41
42
|
if action is None:
|
42
43
|
action = []
|
43
44
|
if sysargs is None:
|
@@ -52,7 +53,6 @@ def api(
|
|
52
53
|
|
53
54
|
from meerschaum.config import get_config
|
54
55
|
from meerschaum.connectors import get_connector
|
55
|
-
requests = attempt_import('requests')
|
56
56
|
if debug:
|
57
57
|
from meerschaum.utils.formatting import pprint
|
58
58
|
api_configs = get_config('meerschaum', 'connectors', 'api', patch=True)
|
@@ -68,12 +68,13 @@ def api(
|
|
68
68
|
del action[0]
|
69
69
|
if len(args_to_send) > 1:
|
70
70
|
del args_to_send[0]
|
71
|
+
|
71
72
|
kw['action'] = action
|
72
73
|
kw['debug'] = debug
|
73
74
|
kw['sysargs'] = args_to_send
|
74
75
|
kw['yes'] = True
|
75
76
|
|
76
|
-
api_conn = get_connector(
|
77
|
+
api_conn = get_connector(f'api:{api_label}')
|
77
78
|
|
78
79
|
if mrsm_instance is not None and str(mrsm_instance) == str(api_conn):
|
79
80
|
warn(
|
@@ -83,9 +84,8 @@ def api(
|
|
83
84
|
elif mrsm_instance is not None:
|
84
85
|
kw['mrsm_instance'] = str(mrsm_instance)
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
msg = f"Action " + ('succeeded' if success else 'failed') + " with message:\n" + str(message)
|
87
|
+
sysargs = parse_dict_to_sysargs(kw)
|
88
|
+
success, message = api_conn.do_action(sysargs)
|
89
89
|
return success, message
|
90
90
|
|
91
91
|
def _api_start(
|
@@ -0,0 +1,113 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
Attach to running jobs.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import meerschaum as mrsm
|
10
|
+
from meerschaum.utils.typing import Optional, List, Any, SuccessTuple
|
11
|
+
|
12
|
+
def attach(
|
13
|
+
action: Optional[List[str]] = None,
|
14
|
+
executor_keys: Optional[str] = None,
|
15
|
+
**kwargs: Any
|
16
|
+
) -> SuccessTuple:
|
17
|
+
"""
|
18
|
+
Attach to a job, and prompt the user when blocking on input.
|
19
|
+
"""
|
20
|
+
from meerschaum.actions import choose_subaction
|
21
|
+
attach_options = {
|
22
|
+
'jobs': _attach_jobs,
|
23
|
+
'logs': _attach_logs,
|
24
|
+
}
|
25
|
+
return choose_subaction(action, attach_options, executor_keys=executor_keys, **kwargs)
|
26
|
+
|
27
|
+
|
28
|
+
def _complete_attach(
|
29
|
+
action: Optional[List[str]] = None,
|
30
|
+
**kw: Any
|
31
|
+
) -> List[str]:
|
32
|
+
"""
|
33
|
+
Override the default Meerschaum `complete_` function.
|
34
|
+
"""
|
35
|
+
from meerschaum.actions.delete import _complete_delete_jobs
|
36
|
+
|
37
|
+
if action is None:
|
38
|
+
action = []
|
39
|
+
|
40
|
+
options = {
|
41
|
+
'job': _complete_delete_jobs,
|
42
|
+
'jobs': _complete_delete_jobs,
|
43
|
+
'log': _complete_delete_jobs,
|
44
|
+
'logs': _complete_delete_jobs,
|
45
|
+
}
|
46
|
+
|
47
|
+
if (
|
48
|
+
len(action) > 0 and action[0] in options
|
49
|
+
and kw.get('line', '').split(' ')[-1] != action[0]
|
50
|
+
):
|
51
|
+
sub = action[0]
|
52
|
+
del action[0]
|
53
|
+
return options[sub](action=action, **kw)
|
54
|
+
|
55
|
+
from meerschaum._internal.shell import default_action_completer
|
56
|
+
return default_action_completer(action=(['attach'] + action), **kw)
|
57
|
+
|
58
|
+
|
59
|
+
def _attach_jobs(
|
60
|
+
action: Optional[List[str]] = None,
|
61
|
+
name: Optional[str] = None,
|
62
|
+
executor_keys: Optional[str] = None,
|
63
|
+
**kwargs: Any
|
64
|
+
) -> SuccessTuple:
|
65
|
+
"""
|
66
|
+
Attach to a job, and prompt the user when blocking on input.
|
67
|
+
"""
|
68
|
+
action = action or []
|
69
|
+
if not action and not name:
|
70
|
+
return False, "Provide the name of the job to attach to."
|
71
|
+
|
72
|
+
name = name or action[0]
|
73
|
+
job = mrsm.Job(name, executor_keys=executor_keys)
|
74
|
+
other_executor_keys = 'systemd' if executor_keys in (None, 'local') else 'local'
|
75
|
+
if not job.exists():
|
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
|
87
|
+
|
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
|
97
|
+
|
98
|
+
return success, message
|
99
|
+
|
100
|
+
|
101
|
+
def _attach_logs(*args, **kwargs) -> SuccessTuple:
|
102
|
+
"""
|
103
|
+
Attach to jobs' logs.
|
104
|
+
"""
|
105
|
+
from meerschaum.actions.show import _show_logs
|
106
|
+
return _show_logs(*args, **kwargs)
|
107
|
+
|
108
|
+
|
109
|
+
### NOTE: This must be the final statement of the module.
|
110
|
+
### Any subactions added below these lines will not
|
111
|
+
### be added to the `help` docstring.
|
112
|
+
from meerschaum.actions import choices_docstring as _choices_docstring
|
113
|
+
attach.__doc__ += _choices_docstring('attach')
|
meerschaum/actions/copy.py
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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 =
|
160
|
+
_keys = (action or []) + connector_keys
|
163
161
|
|
164
162
|
if not _keys:
|
165
163
|
return False, "No connectors to copy."
|
166
164
|
|
167
|
-
|
168
|
-
|
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
|
-
|
175
|
-
pprint(attrs, nopretty=nopretty)
|
168
|
+
ck = _keys[0]
|
176
169
|
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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())
|