multiSSH3 5.85__tar.gz → 5.86__tar.gz
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.
Potentially problematic release.
This version of multiSSH3 might be problematic. Click here for more details.
- {multissh3-5.85 → multissh3-5.86}/PKG-INFO +1 -1
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/PKG-INFO +1 -1
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.py +30 -28
- {multissh3-5.85 → multissh3-5.86}/README.md +0 -0
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/SOURCES.txt +0 -0
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/requires.txt +0 -0
- {multissh3-5.85 → multissh3-5.86}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-5.85 → multissh3-5.86}/setup.cfg +0 -0
- {multissh3-5.85 → multissh3-5.86}/setup.py +0 -0
- {multissh3-5.85 → multissh3-5.86}/test/test.py +0 -0
- {multissh3-5.85 → multissh3-5.86}/test/testCurses.py +0 -0
- {multissh3-5.85 → multissh3-5.86}/test/testCursesOld.py +0 -0
- {multissh3-5.85 → multissh3-5.86}/test/testPerfCompact.py +0 -0
- {multissh3-5.85 → multissh3-5.86}/test/testPerfExpand.py +0 -0
|
@@ -81,10 +81,10 @@ except :
|
|
|
81
81
|
print('Warning: functools.lru_cache is not available, multiSSH3 will run slower without cache.',file=sys.stderr)
|
|
82
82
|
def cache_decorator(func):
|
|
83
83
|
return func
|
|
84
|
-
version = '5.
|
|
84
|
+
version = '5.86'
|
|
85
85
|
VERSION = version
|
|
86
86
|
__version__ = version
|
|
87
|
-
COMMIT_DATE = '2025-
|
|
87
|
+
COMMIT_DATE = '2025-10-07'
|
|
88
88
|
|
|
89
89
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
90
90
|
'~/multiSSH3.config.json',
|
|
@@ -1964,7 +1964,7 @@ def _get_hosts_to_display (hosts, max_num_hosts, hosts_to_display = None, indexO
|
|
|
1964
1964
|
rearrangedHosts.add(host)
|
|
1965
1965
|
return new_hosts_to_display , {'running':len(running_hosts), 'failed':len(failed_hosts), 'finished':len(finished_hosts), 'waiting':len(waiting_hosts)}, rearrangedHosts
|
|
1966
1966
|
|
|
1967
|
-
def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window=DEFAULT_SINGLE_WINDOW, config_reason = 'New Configuration'):
|
|
1967
|
+
def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window=DEFAULT_SINGLE_WINDOW,help_shown = False, config_reason = 'New Configuration'):
|
|
1968
1968
|
global _encoding
|
|
1969
1969
|
_ = config_reason
|
|
1970
1970
|
try:
|
|
@@ -1983,9 +1983,9 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
1983
1983
|
min_line_len_local = max_y-1
|
|
1984
1984
|
# return True if the terminal is too small
|
|
1985
1985
|
if max_x < 2 or max_y < 2:
|
|
1986
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal too small')
|
|
1986
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Terminal too small')
|
|
1987
1987
|
if min_char_len_local < 1 or min_line_len_local < 1:
|
|
1988
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Minimum character or line length too small')
|
|
1988
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Minimum character or line length too small')
|
|
1989
1989
|
# We need to figure out how many hosts we can fit in the terminal
|
|
1990
1990
|
# We will need at least 2 lines per host, one for its name, one for its output
|
|
1991
1991
|
# Each line will be at least 61 characters long (60 for the output, 1 for the borders)
|
|
@@ -1993,10 +1993,10 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
1993
1993
|
max_num_hosts_y = max_y // (min_line_len_local + 1)
|
|
1994
1994
|
max_num_hosts = max_num_hosts_x * max_num_hosts_y
|
|
1995
1995
|
if max_num_hosts < 1:
|
|
1996
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal too small to display any hosts')
|
|
1996
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Terminal too small to display any hosts')
|
|
1997
1997
|
hosts_to_display , host_stats, rearrangedHosts = _get_hosts_to_display(hosts, max_num_hosts)
|
|
1998
1998
|
if len(hosts_to_display) == 0:
|
|
1999
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'No hosts to display')
|
|
1999
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'No hosts to display')
|
|
2000
2000
|
# Now we calculate the actual number of hosts we will display for x and y
|
|
2001
2001
|
optimal_len_x = max(min_char_len_local, 80)
|
|
2002
2002
|
num_hosts_x = min(max(min(max_num_hosts_x, max_x // optimal_len_x),1),len(hosts_to_display))
|
|
@@ -2017,7 +2017,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2017
2017
|
host_window_height = max_y // num_hosts_y
|
|
2018
2018
|
host_window_width = max_x // num_hosts_x
|
|
2019
2019
|
if host_window_height < 1 or host_window_width < 1:
|
|
2020
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Host window too small')
|
|
2020
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Host window too small')
|
|
2021
2021
|
|
|
2022
2022
|
old_stat = ''
|
|
2023
2023
|
old_bottom_stat = ''
|
|
@@ -2078,7 +2078,6 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2078
2078
|
_curses_add_string_to_window(window=help_window,y=12,line='Esc : Clear line', color_pair_list=[-1,-1,1], lead_str='│', box_ansi_color=box_ansi_color)
|
|
2079
2079
|
help_panel = curses.panel.new_panel(help_window)
|
|
2080
2080
|
help_panel.hide()
|
|
2081
|
-
help_shown = False
|
|
2082
2081
|
curses.panel.update_panels()
|
|
2083
2082
|
indexOffset = 0
|
|
2084
2083
|
while host_stats['running'] > 0 or host_stats['waiting'] > 0:
|
|
@@ -2091,7 +2090,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2091
2090
|
# with open('keylog.txt','a') as f:
|
|
2092
2091
|
# f.write(str(key)+'\n')
|
|
2093
2092
|
if key == 410 or key == curses.KEY_RESIZE: # 410 is the key code for resize
|
|
2094
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize requested')
|
|
2093
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Terminal resize requested')
|
|
2095
2094
|
# if the user pressed ctrl + d and the last line is empty, we will exit by adding 'exit\n' to the last line
|
|
2096
2095
|
elif key == 4 and not __keyPressesIn[-1]:
|
|
2097
2096
|
__keyPressesIn[-1].extend('exit\n')
|
|
@@ -2099,20 +2098,20 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2099
2098
|
elif key == 95 and not __keyPressesIn[-1]: # 95 is the key code for _
|
|
2100
2099
|
# if last line is empty, we will reconfigure the wh to be smaller
|
|
2101
2100
|
if min_line_len != 1:
|
|
2102
|
-
return (lineToDisplay,curserPosition , min_char_len , max(min_line_len -1,1), single_window, 'Decrease line length')
|
|
2101
|
+
return (lineToDisplay,curserPosition , min_char_len , max(min_line_len -1,1), single_window,help_shown, 'Decrease line length')
|
|
2103
2102
|
elif key == 43 and not __keyPressesIn[-1]: # 43 is the key code for +
|
|
2104
2103
|
# if last line is empty, we will reconfigure the wh to be larger
|
|
2105
|
-
return (lineToDisplay,curserPosition , min_char_len , min_line_len +1, single_window, 'Increase line length')
|
|
2104
|
+
return (lineToDisplay,curserPosition , min_char_len , min_line_len +1, single_window,help_shown, 'Increase line length')
|
|
2106
2105
|
elif key == 123 and not __keyPressesIn[-1]: # 123 is the key code for {
|
|
2107
2106
|
# if last line is empty, we will reconfigure the ww to be smaller
|
|
2108
2107
|
if min_char_len != 1:
|
|
2109
|
-
return (lineToDisplay,curserPosition , max(min_char_len -1,1), min_line_len, single_window, 'Decrease character length')
|
|
2108
|
+
return (lineToDisplay,curserPosition , max(min_char_len -1,1), min_line_len, single_window,help_shown, 'Decrease character length')
|
|
2110
2109
|
elif key == 124 and not __keyPressesIn[-1]: # 124 is the key code for |
|
|
2111
2110
|
# if last line is empty, we will toggle the single window mode
|
|
2112
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, not single_window, 'Toggle single window mode')
|
|
2111
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, not single_window,help_shown, 'Toggle single window mode')
|
|
2113
2112
|
elif key == 125 and not __keyPressesIn[-1]: # 125 is the key code for }
|
|
2114
2113
|
# if last line is empty, we will reconfigure the ww to be larger
|
|
2115
|
-
return (lineToDisplay,curserPosition , min_char_len +1, min_line_len, single_window, 'Increase character length')
|
|
2114
|
+
return (lineToDisplay,curserPosition , min_char_len +1, min_line_len, single_window,help_shown, 'Increase character length')
|
|
2116
2115
|
elif key == 60 and not __keyPressesIn[-1]: # 60 is the key code for <
|
|
2117
2116
|
indexOffset = (indexOffset - 1 ) % len(hosts)
|
|
2118
2117
|
elif key == 62 and not __keyPressesIn[-1]: # 62 is the key code for >
|
|
@@ -2147,11 +2146,11 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2147
2146
|
curserPosition = len(__keyPressesIn[lineToDisplay])
|
|
2148
2147
|
elif key == curses.KEY_REFRESH or key == curses.KEY_F5 or key == 18: # 18 is the key code for ctrl + R
|
|
2149
2148
|
# if the key is refresh, we will refresh the screen
|
|
2150
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Refresh requested')
|
|
2149
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Refresh requested')
|
|
2151
2150
|
elif key == curses.KEY_EXIT or key == 27: # 27 is the key code for ESC
|
|
2152
2151
|
# if the key is exit, we will exit the program
|
|
2153
2152
|
return
|
|
2154
|
-
elif key == curses.KEY_HELP or key == 63 or key == curses.KEY_F1: # 63 is the key code for ?
|
|
2153
|
+
elif key == curses.KEY_HELP or key == 63 or key == curses.KEY_F1 or key == 8: # 63 is the key code for ?
|
|
2155
2154
|
# if the key is help, we will display the help message
|
|
2156
2155
|
if not help_shown:
|
|
2157
2156
|
help_panel.show()
|
|
@@ -2194,7 +2193,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2194
2193
|
curserPosition += 1
|
|
2195
2194
|
# reconfigure when the terminal size changes
|
|
2196
2195
|
if org_dim != stdscr.getmaxyx():
|
|
2197
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize detected')
|
|
2196
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Terminal resize detected')
|
|
2198
2197
|
# We generate the aggregated stats if user did not input anything
|
|
2199
2198
|
if not __keyPressesIn[lineToDisplay]:
|
|
2200
2199
|
#stats = '┍'+ f" Total: {len(hosts)} Running: {host_stats['running']} Failed: {host_stats['failed']} Finished: {host_stats['finished']} Waiting: {host_stats['waiting']} ww: {min_char_len} wh:{min_line_len} "[:max_x - 2].center(max_x - 2, "━")
|
|
@@ -2268,7 +2267,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2268
2267
|
# print(str(e).strip())
|
|
2269
2268
|
# print(traceback.format_exc().strip())
|
|
2270
2269
|
if org_dim != stdscr.getmaxyx():
|
|
2271
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, 'Terminal resize detected')
|
|
2270
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, 'Terminal resize detected')
|
|
2272
2271
|
if host.lastPrintedUpdateTime != host.lastUpdateTime and host.output_buffer.tell() > 0:
|
|
2273
2272
|
# this means there is still output in the buffer, we will print it
|
|
2274
2273
|
# we will print the output in the window
|
|
@@ -2276,11 +2275,14 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2276
2275
|
host_window.noutrefresh()
|
|
2277
2276
|
host.lastPrintedUpdateTime = host.lastUpdateTime
|
|
2278
2277
|
hosts_to_display, host_stats,rearrangedHosts = _get_hosts_to_display(hosts, max_num_hosts,hosts_to_display, indexOffset)
|
|
2278
|
+
if help_shown:
|
|
2279
|
+
help_window.touchwin()
|
|
2280
|
+
help_window.noutrefresh()
|
|
2279
2281
|
curses.doupdate()
|
|
2280
2282
|
last_refresh_time = time.perf_counter()
|
|
2281
2283
|
except Exception as e:
|
|
2282
2284
|
import traceback
|
|
2283
|
-
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window, f'Error: {str(e)}',traceback.format_exc())
|
|
2285
|
+
return (lineToDisplay,curserPosition , min_char_len, min_line_len, single_window,help_shown, f'Error: {str(e)}',traceback.format_exc())
|
|
2284
2286
|
return None
|
|
2285
2287
|
|
|
2286
2288
|
def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window = DEFAULT_SINGLE_WINDOW):
|
|
@@ -2330,7 +2332,7 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2330
2332
|
stdscr.refresh()
|
|
2331
2333
|
except:
|
|
2332
2334
|
pass
|
|
2333
|
-
params = (-1,0 , min_char_len, min_line_len, single_window,'new config')
|
|
2335
|
+
params = (-1,0 , min_char_len, min_line_len, single_window,False,'new config')
|
|
2334
2336
|
while params:
|
|
2335
2337
|
params = __generate_display(stdscr, hosts, *params)
|
|
2336
2338
|
if not params:
|
|
@@ -2341,17 +2343,17 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2341
2343
|
# print the current configuration
|
|
2342
2344
|
stdscr.clear()
|
|
2343
2345
|
try:
|
|
2344
|
-
stdscr.addstr(0, 0, f"{params[
|
|
2345
|
-
if len(params) >
|
|
2346
|
+
stdscr.addstr(0, 0, f"{params[6]}, Reloading Configuration: min_char_len={params[2]}, min_line_len={params[3]}, single_window={params[4]} with window size {stdscr.getmaxyx()} and {len(hosts)} hosts...")
|
|
2347
|
+
if len(params) > 7:
|
|
2346
2348
|
# traceback is available, print it
|
|
2347
2349
|
i = 1
|
|
2348
|
-
for line in params[
|
|
2350
|
+
for line in params[7].split('\n'):
|
|
2349
2351
|
stdscr.addstr(i, 0, line)
|
|
2350
2352
|
i += 1
|
|
2351
2353
|
stdscr.refresh()
|
|
2352
2354
|
except:
|
|
2353
2355
|
pass
|
|
2354
|
-
params = params[:
|
|
2356
|
+
params = params[:6] + ('new config',)
|
|
2355
2357
|
time.sleep(0.01)
|
|
2356
2358
|
#time.sleep(0.25)
|
|
2357
2359
|
|
|
@@ -3095,9 +3097,9 @@ def get_parser():
|
|
|
3095
3097
|
parser.add_argument("-j","--json", action='store_true', help=F"Output in json format. (default: {DEFAULT_JSON_MODE})", default=DEFAULT_JSON_MODE)
|
|
3096
3098
|
parser.add_argument('-w',"--success_hosts", action='store_true', help=f"Output the hosts that succeeded in summary as well. (default: {DEFAULT_PRINT_SUCCESS_HOSTS})", default=DEFAULT_PRINT_SUCCESS_HOSTS)
|
|
3097
3099
|
parser.add_argument('-P',"-g","--greppable",'--table', action='store_true', help=f"Output in greppable table. (default: {DEFAULT_GREPPABLE_MODE})", default=DEFAULT_GREPPABLE_MODE)
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3100
|
+
su_group = parser.add_mutually_exclusive_group()
|
|
3101
|
+
su_group.add_argument('-x',"-su","--skip_unreachable", action='store_true', help=f"Skip unreachable hosts. Note: Timedout Hosts are considered unreachable. Note: multiple command sequence will still auto skip unreachable hosts. (default: {DEFAULT_SKIP_UNREACHABLE})", default=DEFAULT_SKIP_UNREACHABLE)
|
|
3102
|
+
su_group.add_argument('-a',"-nsu","--no_skip_unreachable",dest = 'skip_unreachable', action='store_false', help=f"Do not skip unreachable hosts. Note: Timedout Hosts are considered unreachable. Note: multiple command sequence will still auto skip unreachable hosts. (default: {not DEFAULT_SKIP_UNREACHABLE})", default=not DEFAULT_SKIP_UNREACHABLE)
|
|
3101
3103
|
parser.add_argument('-uhe','--unavailable_host_expiry', type=int, help=f"Time in seconds to expire the unavailable hosts (default: {DEFAULT_UNAVAILABLE_HOST_EXPIRY})", default=DEFAULT_UNAVAILABLE_HOST_EXPIRY)
|
|
3102
3104
|
parser.add_argument('-X',"-sh","--skip_hosts", type=str, help=f"Skip the hosts in the list. (default: {DEFAULT_SKIP_HOSTS if DEFAULT_SKIP_HOSTS else 'None'})", default=DEFAULT_SKIP_HOSTS)
|
|
3103
3105
|
parser.add_argument('--generate_config_file', action='store_true', help=f'Store / generate the default config file from command line argument and current config at --config_file / stdout')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|