multiSSH3 5.84__py3-none-any.whl → 5.86__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.
Potentially problematic release.
This version of multiSSH3 might be problematic. Click here for more details.
- multiSSH3.py +45 -38
- {multissh3-5.84.dist-info → multissh3-5.86.dist-info}/METADATA +1 -1
- multissh3-5.86.dist-info/RECORD +6 -0
- multissh3-5.84.dist-info/RECORD +0 -6
- {multissh3-5.84.dist-info → multissh3-5.86.dist-info}/WHEEL +0 -0
- {multissh3-5.84.dist-info → multissh3-5.86.dist-info}/entry_points.txt +0 -0
- {multissh3-5.84.dist-info → multissh3-5.86.dist-info}/top_level.txt +0 -0
multiSSH3.py
CHANGED
|
@@ -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-07
|
|
87
|
+
COMMIT_DATE = '2025-10-07'
|
|
88
88
|
|
|
89
89
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
90
90
|
'~/multiSSH3.config.json',
|
|
@@ -624,6 +624,19 @@ def join_threads(threads=__running_threads,timeout=None):
|
|
|
624
624
|
thread.join(timeout=timeout)
|
|
625
625
|
if threads is __running_threads:
|
|
626
626
|
__running_threads = {t for t in threads if t.is_alive()}
|
|
627
|
+
|
|
628
|
+
def format_commands(commands):
|
|
629
|
+
if not commands:
|
|
630
|
+
commands = []
|
|
631
|
+
else:
|
|
632
|
+
commands = [commands] if isinstance(commands,str) else commands
|
|
633
|
+
# reformat commands into a list of strings, join the iterables if they are not strings
|
|
634
|
+
try:
|
|
635
|
+
commands = [' '.join(command) if not isinstance(command,str) else command for command in commands]
|
|
636
|
+
except:
|
|
637
|
+
eprint(f"Warning: commands should ideally be a list of strings. Now mssh had failed to convert {commands!r} to a list of strings. Continuing anyway but expect failures.")
|
|
638
|
+
return commands
|
|
639
|
+
|
|
627
640
|
#%% ------------ Compacting Hostnames ----------------
|
|
628
641
|
def __tokenize_hostname(hostname):
|
|
629
642
|
"""
|
|
@@ -1951,7 +1964,7 @@ def _get_hosts_to_display (hosts, max_num_hosts, hosts_to_display = None, indexO
|
|
|
1951
1964
|
rearrangedHosts.add(host)
|
|
1952
1965
|
return new_hosts_to_display , {'running':len(running_hosts), 'failed':len(failed_hosts), 'finished':len(finished_hosts), 'waiting':len(waiting_hosts)}, rearrangedHosts
|
|
1953
1966
|
|
|
1954
|
-
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'):
|
|
1955
1968
|
global _encoding
|
|
1956
1969
|
_ = config_reason
|
|
1957
1970
|
try:
|
|
@@ -1970,9 +1983,9 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
1970
1983
|
min_line_len_local = max_y-1
|
|
1971
1984
|
# return True if the terminal is too small
|
|
1972
1985
|
if max_x < 2 or max_y < 2:
|
|
1973
|
-
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')
|
|
1974
1987
|
if min_char_len_local < 1 or min_line_len_local < 1:
|
|
1975
|
-
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')
|
|
1976
1989
|
# We need to figure out how many hosts we can fit in the terminal
|
|
1977
1990
|
# We will need at least 2 lines per host, one for its name, one for its output
|
|
1978
1991
|
# Each line will be at least 61 characters long (60 for the output, 1 for the borders)
|
|
@@ -1980,10 +1993,10 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
1980
1993
|
max_num_hosts_y = max_y // (min_line_len_local + 1)
|
|
1981
1994
|
max_num_hosts = max_num_hosts_x * max_num_hosts_y
|
|
1982
1995
|
if max_num_hosts < 1:
|
|
1983
|
-
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')
|
|
1984
1997
|
hosts_to_display , host_stats, rearrangedHosts = _get_hosts_to_display(hosts, max_num_hosts)
|
|
1985
1998
|
if len(hosts_to_display) == 0:
|
|
1986
|
-
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')
|
|
1987
2000
|
# Now we calculate the actual number of hosts we will display for x and y
|
|
1988
2001
|
optimal_len_x = max(min_char_len_local, 80)
|
|
1989
2002
|
num_hosts_x = min(max(min(max_num_hosts_x, max_x // optimal_len_x),1),len(hosts_to_display))
|
|
@@ -2004,7 +2017,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2004
2017
|
host_window_height = max_y // num_hosts_y
|
|
2005
2018
|
host_window_width = max_x // num_hosts_x
|
|
2006
2019
|
if host_window_height < 1 or host_window_width < 1:
|
|
2007
|
-
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')
|
|
2008
2021
|
|
|
2009
2022
|
old_stat = ''
|
|
2010
2023
|
old_bottom_stat = ''
|
|
@@ -2065,7 +2078,6 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2065
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)
|
|
2066
2079
|
help_panel = curses.panel.new_panel(help_window)
|
|
2067
2080
|
help_panel.hide()
|
|
2068
|
-
help_shown = False
|
|
2069
2081
|
curses.panel.update_panels()
|
|
2070
2082
|
indexOffset = 0
|
|
2071
2083
|
while host_stats['running'] > 0 or host_stats['waiting'] > 0:
|
|
@@ -2078,7 +2090,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2078
2090
|
# with open('keylog.txt','a') as f:
|
|
2079
2091
|
# f.write(str(key)+'\n')
|
|
2080
2092
|
if key == 410 or key == curses.KEY_RESIZE: # 410 is the key code for resize
|
|
2081
|
-
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')
|
|
2082
2094
|
# if the user pressed ctrl + d and the last line is empty, we will exit by adding 'exit\n' to the last line
|
|
2083
2095
|
elif key == 4 and not __keyPressesIn[-1]:
|
|
2084
2096
|
__keyPressesIn[-1].extend('exit\n')
|
|
@@ -2086,20 +2098,20 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2086
2098
|
elif key == 95 and not __keyPressesIn[-1]: # 95 is the key code for _
|
|
2087
2099
|
# if last line is empty, we will reconfigure the wh to be smaller
|
|
2088
2100
|
if min_line_len != 1:
|
|
2089
|
-
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')
|
|
2090
2102
|
elif key == 43 and not __keyPressesIn[-1]: # 43 is the key code for +
|
|
2091
2103
|
# if last line is empty, we will reconfigure the wh to be larger
|
|
2092
|
-
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')
|
|
2093
2105
|
elif key == 123 and not __keyPressesIn[-1]: # 123 is the key code for {
|
|
2094
2106
|
# if last line is empty, we will reconfigure the ww to be smaller
|
|
2095
2107
|
if min_char_len != 1:
|
|
2096
|
-
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')
|
|
2097
2109
|
elif key == 124 and not __keyPressesIn[-1]: # 124 is the key code for |
|
|
2098
2110
|
# if last line is empty, we will toggle the single window mode
|
|
2099
|
-
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')
|
|
2100
2112
|
elif key == 125 and not __keyPressesIn[-1]: # 125 is the key code for }
|
|
2101
2113
|
# if last line is empty, we will reconfigure the ww to be larger
|
|
2102
|
-
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')
|
|
2103
2115
|
elif key == 60 and not __keyPressesIn[-1]: # 60 is the key code for <
|
|
2104
2116
|
indexOffset = (indexOffset - 1 ) % len(hosts)
|
|
2105
2117
|
elif key == 62 and not __keyPressesIn[-1]: # 62 is the key code for >
|
|
@@ -2134,11 +2146,11 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2134
2146
|
curserPosition = len(__keyPressesIn[lineToDisplay])
|
|
2135
2147
|
elif key == curses.KEY_REFRESH or key == curses.KEY_F5 or key == 18: # 18 is the key code for ctrl + R
|
|
2136
2148
|
# if the key is refresh, we will refresh the screen
|
|
2137
|
-
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')
|
|
2138
2150
|
elif key == curses.KEY_EXIT or key == 27: # 27 is the key code for ESC
|
|
2139
2151
|
# if the key is exit, we will exit the program
|
|
2140
2152
|
return
|
|
2141
|
-
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 ?
|
|
2142
2154
|
# if the key is help, we will display the help message
|
|
2143
2155
|
if not help_shown:
|
|
2144
2156
|
help_panel.show()
|
|
@@ -2181,7 +2193,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2181
2193
|
curserPosition += 1
|
|
2182
2194
|
# reconfigure when the terminal size changes
|
|
2183
2195
|
if org_dim != stdscr.getmaxyx():
|
|
2184
|
-
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')
|
|
2185
2197
|
# We generate the aggregated stats if user did not input anything
|
|
2186
2198
|
if not __keyPressesIn[lineToDisplay]:
|
|
2187
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, "━")
|
|
@@ -2255,7 +2267,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2255
2267
|
# print(str(e).strip())
|
|
2256
2268
|
# print(traceback.format_exc().strip())
|
|
2257
2269
|
if org_dim != stdscr.getmaxyx():
|
|
2258
|
-
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')
|
|
2259
2271
|
if host.lastPrintedUpdateTime != host.lastUpdateTime and host.output_buffer.tell() > 0:
|
|
2260
2272
|
# this means there is still output in the buffer, we will print it
|
|
2261
2273
|
# we will print the output in the window
|
|
@@ -2263,11 +2275,14 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2263
2275
|
host_window.noutrefresh()
|
|
2264
2276
|
host.lastPrintedUpdateTime = host.lastUpdateTime
|
|
2265
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()
|
|
2266
2281
|
curses.doupdate()
|
|
2267
2282
|
last_refresh_time = time.perf_counter()
|
|
2268
2283
|
except Exception as e:
|
|
2269
2284
|
import traceback
|
|
2270
|
-
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())
|
|
2271
2286
|
return None
|
|
2272
2287
|
|
|
2273
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):
|
|
@@ -2317,7 +2332,7 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2317
2332
|
stdscr.refresh()
|
|
2318
2333
|
except:
|
|
2319
2334
|
pass
|
|
2320
|
-
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')
|
|
2321
2336
|
while params:
|
|
2322
2337
|
params = __generate_display(stdscr, hosts, *params)
|
|
2323
2338
|
if not params:
|
|
@@ -2328,17 +2343,17 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2328
2343
|
# print the current configuration
|
|
2329
2344
|
stdscr.clear()
|
|
2330
2345
|
try:
|
|
2331
|
-
stdscr.addstr(0, 0, f"{params[
|
|
2332
|
-
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:
|
|
2333
2348
|
# traceback is available, print it
|
|
2334
2349
|
i = 1
|
|
2335
|
-
for line in params[
|
|
2350
|
+
for line in params[7].split('\n'):
|
|
2336
2351
|
stdscr.addstr(i, 0, line)
|
|
2337
2352
|
i += 1
|
|
2338
2353
|
stdscr.refresh()
|
|
2339
2354
|
except:
|
|
2340
2355
|
pass
|
|
2341
|
-
params = params[:
|
|
2356
|
+
params = params[:6] + ('new config',)
|
|
2342
2357
|
time.sleep(0.01)
|
|
2343
2358
|
#time.sleep(0.25)
|
|
2344
2359
|
|
|
@@ -2612,7 +2627,7 @@ def getStrCommand(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAULT_ONE_O
|
|
|
2612
2627
|
history_file = history_file, env_file = env_file,
|
|
2613
2628
|
repeat = repeat,interval = interval,
|
|
2614
2629
|
shortend = shortend)
|
|
2615
|
-
commands = [command.replace('"', '\\"').replace('\n', '\\n').replace('\t', '\\t') for command in commands]
|
|
2630
|
+
commands = [command.replace('"', '\\"').replace('\n', '\\n').replace('\t', '\\t') for command in format_commands(commands)]
|
|
2616
2631
|
commandStr = '"' + '" "'.join(commands) + '"' if commands else ''
|
|
2617
2632
|
filePath = os.path.abspath(__file__)
|
|
2618
2633
|
programName = filePath if filePath else 'mssh'
|
|
@@ -2761,15 +2776,7 @@ def run_command_on_hosts(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAUL
|
|
|
2761
2776
|
if max_connections > __max_connections_nofile_limit_supported * 2:
|
|
2762
2777
|
# we need to throttle thread start to avoid hitting the nofile limit
|
|
2763
2778
|
__thread_start_delay = 0.001
|
|
2764
|
-
|
|
2765
|
-
commands = []
|
|
2766
|
-
else:
|
|
2767
|
-
commands = [commands] if isinstance(commands,str) else commands
|
|
2768
|
-
# reformat commands into a list of strings, join the iterables if they are not strings
|
|
2769
|
-
try:
|
|
2770
|
-
commands = [' '.join(command) if not isinstance(command,str) else command for command in commands]
|
|
2771
|
-
except:
|
|
2772
|
-
eprint(f"Warning: commands should ideally be a list of strings. Now mssh had failed to convert {commands!r} to a list of strings. Continuing anyway but expect failures.")
|
|
2779
|
+
commands = format_commands(commands)
|
|
2773
2780
|
#verify_ssh_config()
|
|
2774
2781
|
# load global unavailable hosts only if the function is called (so using --repeat will not load the unavailable hosts again)
|
|
2775
2782
|
if called:
|
|
@@ -3090,9 +3097,9 @@ def get_parser():
|
|
|
3090
3097
|
parser.add_argument("-j","--json", action='store_true', help=F"Output in json format. (default: {DEFAULT_JSON_MODE})", default=DEFAULT_JSON_MODE)
|
|
3091
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)
|
|
3092
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)
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
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)
|
|
3096
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)
|
|
3097
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)
|
|
3098
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')
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
multiSSH3.py,sha256=Mbr7AsHObwHIkMCuS9bsfmfMFWNQ4NngBlM-oVCXAlg,154547
|
|
2
|
+
multissh3-5.86.dist-info/METADATA,sha256=r4ndEU9KGZ5RMn-AtlxzUazkrnbLbT7LFkQWgF9RwqY,18093
|
|
3
|
+
multissh3-5.86.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
+
multissh3-5.86.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
+
multissh3-5.86.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
+
multissh3-5.86.dist-info/RECORD,,
|
multissh3-5.84.dist-info/RECORD
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
multiSSH3.py,sha256=-CzKDCUgMrgzmvtiLGgbQG0n_Gzk6IEqvUieLzJ29y0,154177
|
|
2
|
-
multissh3-5.84.dist-info/METADATA,sha256=9ZD6QwIhVXZXymckMv_aocvIzy2NHjyA_EnDaUhZn1s,18093
|
|
3
|
-
multissh3-5.84.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
-
multissh3-5.84.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
-
multissh3-5.84.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
-
multissh3-5.84.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|