meerschaum 2.2.6__py3-none-any.whl → 2.3.0.dev1__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 +4 -1
- meerschaum/__main__.py +10 -5
- meerschaum/_internal/arguments/_parser.py +44 -15
- meerschaum/_internal/entry.py +35 -14
- meerschaum/_internal/shell/Shell.py +155 -53
- meerschaum/_internal/shell/updates.py +175 -0
- meerschaum/actions/api.py +12 -12
- meerschaum/actions/attach.py +95 -0
- meerschaum/actions/delete.py +35 -26
- meerschaum/actions/register.py +19 -5
- meerschaum/actions/show.py +119 -148
- meerschaum/actions/start.py +85 -75
- meerschaum/actions/stop.py +68 -39
- meerschaum/actions/sync.py +3 -3
- meerschaum/actions/upgrade.py +28 -36
- meerschaum/api/_events.py +18 -1
- meerschaum/api/_oauth2.py +2 -0
- meerschaum/api/_websockets.py +2 -2
- meerschaum/api/dash/jobs.py +5 -2
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +122 -44
- meerschaum/api/routes/_jobs.py +340 -0
- meerschaum/api/routes/_pipes.py +25 -25
- meerschaum/config/_default.py +1 -0
- meerschaum/config/_formatting.py +1 -0
- meerschaum/config/_paths.py +5 -0
- meerschaum/config/_shell.py +84 -67
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +9 -0
- meerschaum/connectors/__init__.py +9 -11
- meerschaum/connectors/api/APIConnector.py +18 -1
- meerschaum/connectors/api/_actions.py +60 -71
- meerschaum/connectors/api/_jobs.py +260 -0
- meerschaum/connectors/api/_misc.py +1 -1
- meerschaum/connectors/api/_request.py +13 -9
- meerschaum/connectors/parse.py +23 -7
- meerschaum/core/Pipe/_sync.py +3 -0
- meerschaum/plugins/__init__.py +89 -5
- meerschaum/utils/daemon/Daemon.py +333 -149
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +19 -10
- meerschaum/utils/daemon/RotatingFile.py +18 -7
- meerschaum/utils/daemon/StdinFile.py +110 -0
- meerschaum/utils/daemon/__init__.py +40 -27
- meerschaum/utils/formatting/__init__.py +83 -37
- meerschaum/utils/formatting/_jobs.py +118 -51
- meerschaum/utils/formatting/_shell.py +6 -0
- meerschaum/utils/jobs/_Job.py +684 -0
- meerschaum/utils/jobs/__init__.py +245 -0
- meerschaum/utils/misc.py +18 -17
- meerschaum/utils/packages/__init__.py +21 -15
- meerschaum/utils/packages/_packages.py +2 -2
- meerschaum/utils/prompt.py +20 -7
- meerschaum/utils/schedule.py +21 -15
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/METADATA +9 -9
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/RECORD +61 -54
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/WHEEL +1 -1
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.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/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,95 @@
|
|
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
|
+
**kwargs: Any
|
15
|
+
) -> SuccessTuple:
|
16
|
+
"""
|
17
|
+
Attach to a job.
|
18
|
+
"""
|
19
|
+
from meerschaum.actions import choose_subaction
|
20
|
+
attach_options = {
|
21
|
+
'jobs': _attach_jobs,
|
22
|
+
'logs': _attach_logs,
|
23
|
+
}
|
24
|
+
return choose_subaction(action, attach_options, **kwargs)
|
25
|
+
|
26
|
+
|
27
|
+
def _complete_attach(
|
28
|
+
action: Optional[List[str]] = None,
|
29
|
+
**kw: Any
|
30
|
+
) -> List[str]:
|
31
|
+
"""
|
32
|
+
Override the default Meerschaum `complete_` function.
|
33
|
+
"""
|
34
|
+
from meerschaum.actions.start import _complete_start_jobs
|
35
|
+
|
36
|
+
if action is None:
|
37
|
+
action = []
|
38
|
+
|
39
|
+
options = {
|
40
|
+
'job': _complete_start_jobs,
|
41
|
+
'jobs': _complete_start_jobs,
|
42
|
+
'log': _complete_start_jobs,
|
43
|
+
'logs': _complete_start_jobs,
|
44
|
+
}
|
45
|
+
|
46
|
+
if (
|
47
|
+
len(action) > 0 and action[0] in options
|
48
|
+
and kw.get('line', '').split(' ')[-1] != action[0]
|
49
|
+
):
|
50
|
+
sub = action[0]
|
51
|
+
del action[0]
|
52
|
+
return options[sub](action=action, **kw)
|
53
|
+
|
54
|
+
from meerschaum._internal.shell import default_action_completer
|
55
|
+
return default_action_completer(action=(['attach'] + action), **kw)
|
56
|
+
|
57
|
+
|
58
|
+
def _attach_jobs(
|
59
|
+
action: Optional[List[str]] = None,
|
60
|
+
name: Optional[str] = None,
|
61
|
+
executor_keys: Optional[str] = None,
|
62
|
+
**kwargs: Any
|
63
|
+
) -> SuccessTuple:
|
64
|
+
"""
|
65
|
+
Attach to a job, and prompt the user when blocking on input.
|
66
|
+
"""
|
67
|
+
if not action and not name:
|
68
|
+
return False, "Provide the name of the job to attach to."
|
69
|
+
|
70
|
+
name = name or action[0]
|
71
|
+
job = mrsm.Job(name, executor_keys=executor_keys)
|
72
|
+
if not job.exists():
|
73
|
+
return False, f"Job '{job.name}' does not exist."
|
74
|
+
|
75
|
+
job.monitor_logs(
|
76
|
+
stop_on_exit=True,
|
77
|
+
strip_timestamps=True,
|
78
|
+
)
|
79
|
+
|
80
|
+
return True, "Success"
|
81
|
+
|
82
|
+
|
83
|
+
def _attach_logs(*args, **kwargs) -> SuccessTuple:
|
84
|
+
"""
|
85
|
+
Attach to jobs' logs.
|
86
|
+
"""
|
87
|
+
from meerschaum.actions.show import _show_logs
|
88
|
+
return _show_logs(*args, **kwargs)
|
89
|
+
|
90
|
+
|
91
|
+
### NOTE: This must be the final statement of the module.
|
92
|
+
### Any subactions added below these lines will not
|
93
|
+
### be added to the `help` docstring.
|
94
|
+
from meerschaum.actions import choices_docstring as _choices_docstring
|
95
|
+
attach.__doc__ += _choices_docstring('attach')
|
meerschaum/actions/delete.py
CHANGED
@@ -391,6 +391,7 @@ def _complete_delete_connectors(
|
|
391
391
|
|
392
392
|
def _delete_jobs(
|
393
393
|
action: Optional[List[str]] = None,
|
394
|
+
executor_keys: Optional[str] = None,
|
394
395
|
noask: bool = False,
|
395
396
|
nopretty: bool = False,
|
396
397
|
force: bool = False,
|
@@ -404,8 +405,12 @@ def _delete_jobs(
|
|
404
405
|
If the job is running, ask to kill the job first.
|
405
406
|
|
406
407
|
"""
|
407
|
-
from meerschaum.utils.
|
408
|
-
|
408
|
+
from meerschaum.utils.jobs import (
|
409
|
+
Job,
|
410
|
+
get_running_jobs,
|
411
|
+
get_stopped_jobs,
|
412
|
+
get_filtered_jobs,
|
413
|
+
get_paused_jobs,
|
409
414
|
)
|
410
415
|
from meerschaum.utils.prompt import yes_no
|
411
416
|
from meerschaum.utils.formatting._jobs import pprint_jobs
|
@@ -413,49 +418,53 @@ def _delete_jobs(
|
|
413
418
|
from meerschaum.utils.warnings import warn
|
414
419
|
from meerschaum.utils.misc import items_str
|
415
420
|
from meerschaum.actions import actions
|
416
|
-
|
417
|
-
|
421
|
+
|
422
|
+
jobs = get_filtered_jobs(executor_keys, action, debug=debug)
|
423
|
+
if not jobs:
|
418
424
|
return True, "No jobs to delete; nothing to do."
|
419
425
|
|
420
426
|
_delete_all_jobs = False
|
421
427
|
if not action:
|
422
428
|
if not force:
|
423
|
-
pprint_jobs(
|
429
|
+
pprint_jobs(jobs)
|
424
430
|
if not yes_no(
|
425
431
|
"Delete all jobs? This cannot be undone!",
|
426
432
|
noask=noask, yes=yes, default='n'
|
427
433
|
):
|
428
434
|
return False, "No jobs were deleted."
|
435
|
+
|
429
436
|
_delete_all_jobs = True
|
430
|
-
_running_daemons = get_running_daemons(daemons)
|
431
|
-
_paused_daemons = get_paused_daemons(daemons)
|
432
|
-
_stopped_daemons = get_stopped_daemons(daemons)
|
433
|
-
_to_delete = _stopped_daemons
|
434
437
|
|
435
|
-
|
436
|
-
|
438
|
+
_running_jobs = get_running_jobs(executor_keys, jobs, debug=debug)
|
439
|
+
_paused_jobs = get_paused_jobs(executor_keys, jobs, debug=debug)
|
440
|
+
_stopped_jobs = get_stopped_jobs(executor_keys, jobs, debug=debug)
|
441
|
+
_to_delete = _stopped_jobs
|
442
|
+
|
443
|
+
to_stop_jobs = {**_running_jobs, **_paused_jobs}
|
444
|
+
if to_stop_jobs:
|
437
445
|
clear_screen(debug=debug)
|
438
446
|
if not force:
|
439
|
-
pprint_jobs(
|
447
|
+
pprint_jobs(to_stop_jobs, nopretty=nopretty)
|
440
448
|
if force or yes_no(
|
441
449
|
"Stop these jobs?",
|
442
450
|
default='n', yes=yes, noask=noask
|
443
451
|
):
|
444
452
|
actions['stop'](
|
445
|
-
action
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
453
|
+
action=(['jobs'] + [_name for _name in to_stop_jobs]),
|
454
|
+
executor_keys=executor_keys,
|
455
|
+
nopretty=nopretty,
|
456
|
+
yes=yes,
|
457
|
+
force=force,
|
458
|
+
noask=noask,
|
459
|
+
debug=debug,
|
451
460
|
**kw
|
452
461
|
)
|
453
462
|
### Ensure the running jobs are dead.
|
454
|
-
if
|
463
|
+
if get_running_jobs(executor_keys, jobs, debug=debug):
|
455
464
|
return False, (
|
456
465
|
f"Failed to kill running jobs. Please stop these jobs before deleting."
|
457
466
|
)
|
458
|
-
_to_delete
|
467
|
+
_to_delete.update(to_stop_jobs)
|
459
468
|
|
460
469
|
### User decided not to kill running jobs.
|
461
470
|
else:
|
@@ -473,17 +482,17 @@ def _delete_jobs(
|
|
473
482
|
return False, "No jobs were deleted."
|
474
483
|
|
475
484
|
_deleted = []
|
476
|
-
for
|
477
|
-
|
478
|
-
if
|
479
|
-
warn(f"Failed to delete job '{
|
485
|
+
for name, job in _to_delete.items():
|
486
|
+
delete_success, delete_msg = job.delete()
|
487
|
+
if not delete_success:
|
488
|
+
warn(f"Failed to delete job '{name}'.", stack=False)
|
480
489
|
continue
|
481
|
-
_deleted.append(
|
490
|
+
_deleted.append(name)
|
482
491
|
|
483
492
|
return (
|
484
493
|
len(_deleted) > 0,
|
485
494
|
("Deleted job" + ("s" if len(_deleted) != 1 else '')
|
486
|
-
+ f" {items_str([
|
495
|
+
+ f" {items_str([_name for _name in _deleted])}."),
|
487
496
|
)
|
488
497
|
|
489
498
|
|
meerschaum/actions/register.py
CHANGED
@@ -203,14 +203,23 @@ def _register_plugins(
|
|
203
203
|
successes = {}
|
204
204
|
|
205
205
|
for name, plugin in plugins_to_register.items():
|
206
|
-
desc = None
|
207
206
|
plugin.attributes = repo_connector.get_plugin_attributes(plugin, debug=debug)
|
208
207
|
if plugin.attributes is None:
|
209
208
|
plugin.attributes = {}
|
209
|
+
|
210
|
+
try:
|
211
|
+
description_text = plugin.attributes.get('description', '')
|
212
|
+
doc_text = plugin.module.__doc__.lstrip().rstrip()
|
213
|
+
except Exception:
|
214
|
+
description_text = ''
|
215
|
+
doc_text = ''
|
216
|
+
|
217
|
+
desc = description_text or doc_text or ''
|
218
|
+
|
210
219
|
question = f"Would you like to add a description to plugin '{name}'?"
|
211
|
-
if
|
220
|
+
if desc:
|
212
221
|
info(f"Found existing description for plugin '{plugin}':")
|
213
|
-
print(
|
222
|
+
print(desc)
|
214
223
|
question = (
|
215
224
|
"Would you like to overwrite this description?\n"
|
216
225
|
+ "To edit the existing text, visit /dash/plugins for this repository."
|
@@ -220,9 +229,14 @@ def _register_plugins(
|
|
220
229
|
default='n',
|
221
230
|
yes=yes
|
222
231
|
):
|
223
|
-
info('Press (Esc + Enter) to submit
|
232
|
+
info('Press (Esc + Enter) to submit, (CTRL + C) to cancel.')
|
224
233
|
try:
|
225
|
-
desc = prompt(
|
234
|
+
desc = prompt(
|
235
|
+
'',
|
236
|
+
multiline=True,
|
237
|
+
icon=False,
|
238
|
+
default_editable=desc.lstrip().rstrip(),
|
239
|
+
)
|
226
240
|
except KeyboardInterrupt:
|
227
241
|
desc = None
|
228
242
|
if desc == '':
|