multiSSH3 5.74__py3-none-any.whl → 5.75__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 +20 -9
- {multissh3-5.74.dist-info → multissh3-5.75.dist-info}/METADATA +1 -1
- multissh3-5.75.dist-info/RECORD +6 -0
- multissh3-5.74.dist-info/RECORD +0 -6
- {multissh3-5.74.dist-info → multissh3-5.75.dist-info}/WHEEL +0 -0
- {multissh3-5.74.dist-info → multissh3-5.75.dist-info}/entry_points.txt +0 -0
- {multissh3-5.74.dist-info → multissh3-5.75.dist-info}/top_level.txt +0 -0
multiSSH3.py
CHANGED
|
@@ -55,10 +55,10 @@ except AttributeError:
|
|
|
55
55
|
# If neither is available, use a dummy decorator
|
|
56
56
|
def cache_decorator(func):
|
|
57
57
|
return func
|
|
58
|
-
version = '5.
|
|
58
|
+
version = '5.75'
|
|
59
59
|
VERSION = version
|
|
60
60
|
__version__ = version
|
|
61
|
-
COMMIT_DATE = '2025-06-
|
|
61
|
+
COMMIT_DATE = '2025-06-17'
|
|
62
62
|
|
|
63
63
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
64
64
|
'~/multiSSH3.config.json',
|
|
@@ -313,6 +313,7 @@ DEFAULT_PRINT_SUCCESS_HOSTS = False
|
|
|
313
313
|
DEFAULT_GREPPABLE_MODE = False
|
|
314
314
|
DEFAULT_SKIP_UNREACHABLE = True
|
|
315
315
|
DEFAULT_SKIP_HOSTS = ''
|
|
316
|
+
DEFAULT_ENCODING = 'utf-8'
|
|
316
317
|
SSH_STRICT_HOST_KEY_CHECKING = False
|
|
317
318
|
ERROR_MESSAGES_TO_IGNORE = [
|
|
318
319
|
'Pseudo-terminal will not be allocated because stdin is not a terminal',
|
|
@@ -360,6 +361,7 @@ __curses_color_table = {}
|
|
|
360
361
|
__curses_current_color_index = 10
|
|
361
362
|
__max_connections_nofile_limit_supported = 0
|
|
362
363
|
__thread_start_delay = 0
|
|
364
|
+
_encoding = DEFAULT_ENCODING
|
|
363
365
|
if __resource_lib_available:
|
|
364
366
|
# Get the current limits
|
|
365
367
|
_, __system_nofile_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
|
|
@@ -1123,11 +1125,12 @@ def __handle_reading_stream(stream,target, host):
|
|
|
1123
1125
|
Returns:
|
|
1124
1126
|
None
|
|
1125
1127
|
'''
|
|
1128
|
+
global _encoding
|
|
1126
1129
|
def add_line(current_line,target, host, keepLastLine=True):
|
|
1127
1130
|
if not keepLastLine:
|
|
1128
1131
|
target.pop()
|
|
1129
1132
|
host.output.pop()
|
|
1130
|
-
current_line_str = current_line.decode(
|
|
1133
|
+
current_line_str = current_line.decode(_encoding,errors='backslashreplace')
|
|
1131
1134
|
target.append(current_line_str)
|
|
1132
1135
|
host.output.append(current_line_str)
|
|
1133
1136
|
host.lineNumToPrintSet.add(len(host.output)-1)
|
|
@@ -1158,7 +1161,7 @@ def __handle_reading_stream(stream,target, host):
|
|
|
1158
1161
|
current_line.append(char[0])
|
|
1159
1162
|
else:
|
|
1160
1163
|
# curser is bigger than the length of the line
|
|
1161
|
-
current_line += b' '*(curser_position - len(current_line)) + char
|
|
1164
|
+
current_line += b' '*(curser_position - len(current_line)) + char[0]
|
|
1162
1165
|
curser_position += 1
|
|
1163
1166
|
if time.monotonic() - previousUpdateTime > 0.1:
|
|
1164
1167
|
# if the time since the last update is more than 10ms, we update the output
|
|
@@ -1181,15 +1184,16 @@ def __handle_writing_stream(stream,stop_event,host):
|
|
|
1181
1184
|
None
|
|
1182
1185
|
'''
|
|
1183
1186
|
global __keyPressesIn
|
|
1187
|
+
global _encoding
|
|
1184
1188
|
# __keyPressesIn is a list of lists.
|
|
1185
1189
|
# Each list is a list of characters to be sent to the stdin of the process at once.
|
|
1186
1190
|
# We do not send the last line as it may be incomplete.
|
|
1187
1191
|
sentInput = 0
|
|
1188
1192
|
while not stop_event.is_set():
|
|
1189
1193
|
if sentInput < len(__keyPressesIn) - 1 :
|
|
1190
|
-
stream.write(''.join(__keyPressesIn[sentInput]).encode())
|
|
1194
|
+
stream.write(''.join(__keyPressesIn[sentInput]).encode(encoding=_encoding,errors='backslashreplace'))
|
|
1191
1195
|
stream.flush()
|
|
1192
|
-
line = '> ' + ''.join(__keyPressesIn[sentInput]).encode().decode().replace('\n', '↵')
|
|
1196
|
+
line = '> ' + ''.join(__keyPressesIn[sentInput]).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\n', '↵')
|
|
1193
1197
|
host.output.append(line)
|
|
1194
1198
|
host.stdout.append(line)
|
|
1195
1199
|
host.lineNumToPrintSet.add(len(host.output)-1)
|
|
@@ -1866,6 +1870,7 @@ def _get_hosts_to_display (hosts, max_num_hosts, hosts_to_display = None, indexO
|
|
|
1866
1870
|
return new_hosts_to_display , {'running':len(running_hosts), 'failed':len(failed_hosts), 'finished':len(finished_hosts), 'waiting':len(waiting_hosts)}, rearrangedHosts
|
|
1867
1871
|
|
|
1868
1872
|
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'):
|
|
1873
|
+
global _encoding
|
|
1869
1874
|
_ = config_reason
|
|
1870
1875
|
try:
|
|
1871
1876
|
box_ansi_color = None
|
|
@@ -2101,7 +2106,7 @@ def __generate_display(stdscr, hosts, lineToDisplay = -1,curserPosition = 0, min
|
|
|
2101
2106
|
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} i:{indexOffset} "
|
|
2102
2107
|
else:
|
|
2103
2108
|
# we use the stat bar to display the key presses
|
|
2104
|
-
encodedLine = ''.join(__keyPressesIn[lineToDisplay]).encode().decode().strip('\n') + ' '
|
|
2109
|
+
encodedLine = ''.join(__keyPressesIn[lineToDisplay]).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').strip('\n') + ' '
|
|
2105
2110
|
#stats = '┍'+ f"Send CMD: {encodedLine}"[:max_x - 2].center(max_x - 2, "━")
|
|
2106
2111
|
# format the stats line with chracter at curser position inverted using ansi escape sequence
|
|
2107
2112
|
# displayCurserPosition is needed as the curserPosition can be larger than the length of the encodedLine. This is wanted to keep scrolling through the history less painful
|
|
@@ -2253,6 +2258,7 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2253
2258
|
def generate_output(hosts, usejson = False, greppable = False):
|
|
2254
2259
|
global __keyPressesIn
|
|
2255
2260
|
global __global_suppress_printout
|
|
2261
|
+
global __encoding
|
|
2256
2262
|
if __global_suppress_printout:
|
|
2257
2263
|
# remove hosts with returncode 0
|
|
2258
2264
|
hosts = [dict(host) for host in hosts if host.returncode != 0]
|
|
@@ -2286,7 +2292,7 @@ def generate_output(hosts, usejson = False, greppable = False):
|
|
|
2286
2292
|
rtnStr += pretty_format_table(rtnList)
|
|
2287
2293
|
rtnStr += '*'*80+'\n'
|
|
2288
2294
|
if __keyPressesIn[-1]:
|
|
2289
|
-
CMDsOut = [''.join(cmd).encode('
|
|
2295
|
+
CMDsOut = [''.join(cmd).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
|
|
2290
2296
|
rtnStr += 'User Inputs: '+ '\nUser Inputs: '.join(CMDsOut)
|
|
2291
2297
|
#rtnStr += '\n'
|
|
2292
2298
|
else:
|
|
@@ -2317,7 +2323,7 @@ def generate_output(hosts, usejson = False, greppable = False):
|
|
|
2317
2323
|
if not __global_suppress_printout or outputs:
|
|
2318
2324
|
rtnStr += '*'*80+'\n'
|
|
2319
2325
|
if __keyPressesIn[-1]:
|
|
2320
|
-
CMDsOut = [''.join(cmd).encode('
|
|
2326
|
+
CMDsOut = [''.join(cmd).encode(encoding=_encoding,errors='backslashreplace').decode(encoding=_encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
|
|
2321
2327
|
#rtnStr += f"Key presses: {''.join(__keyPressesIn).encode('unicode_escape').decode()}\n"
|
|
2322
2328
|
#rtnStr += f"Key presses: {__keyPressesIn}\n"
|
|
2323
2329
|
rtnStr += "User Inputs: \n "
|
|
@@ -2915,6 +2921,7 @@ def generate_default_config(args):
|
|
|
2915
2921
|
'DEFAULT_GREPPABLE_MODE': args.greppable,
|
|
2916
2922
|
'DEFAULT_SKIP_UNREACHABLE': args.skip_unreachable,
|
|
2917
2923
|
'DEFAULT_SKIP_HOSTS': args.skip_hosts,
|
|
2924
|
+
'DEFAULT_ENCODING': args.encoding,
|
|
2918
2925
|
'SSH_STRICT_HOST_KEY_CHECKING': SSH_STRICT_HOST_KEY_CHECKING,
|
|
2919
2926
|
'ERROR_MESSAGES_TO_IGNORE': ERROR_MESSAGES_TO_IGNORE,
|
|
2920
2927
|
}
|
|
@@ -2970,6 +2977,7 @@ def main():
|
|
|
2970
2977
|
global _env_file
|
|
2971
2978
|
global __DEBUG_MODE
|
|
2972
2979
|
global __configs_from_file
|
|
2980
|
+
global _encoding
|
|
2973
2981
|
_emo = False
|
|
2974
2982
|
# We handle the signal
|
|
2975
2983
|
signal.signal(signal.SIGINT, signal_handler)
|
|
@@ -3021,6 +3029,7 @@ def main():
|
|
|
3021
3029
|
parser.add_argument('-I','-nh','--no_history', action='store_true', help=f'Do not record the command to history. Default: {DEFAULT_NO_HISTORY}', default=DEFAULT_NO_HISTORY)
|
|
3022
3030
|
parser.add_argument('-hf','--history_file', type=str, help=f'The file to store the history. (default: {DEFAULT_HISTORY_FILE})', default=DEFAULT_HISTORY_FILE)
|
|
3023
3031
|
parser.add_argument('--script', action='store_true', help='Run the command in script mode, short for -SCRIPT or --no_watch --skip_unreachable --no_env --no_history --greppable --error_only')
|
|
3032
|
+
parser.add_argument('-e','--encoding', type=str, help=f'The encoding to use for the output. (default: {DEFAULT_ENCODING})', default=DEFAULT_ENCODING)
|
|
3024
3033
|
parser.add_argument("-V","--version", action='version', version=f'%(prog)s {version} @ {COMMIT_DATE} with [ {", ".join(_binPaths.keys())} ] by {AUTHOR} ({AUTHOR_EMAIL})')
|
|
3025
3034
|
|
|
3026
3035
|
# parser.add_argument('-u', '--user', metavar='user', type=str, nargs=1,
|
|
@@ -3109,6 +3118,8 @@ def main():
|
|
|
3109
3118
|
# set timeout to the default script timeout if timeout is not set
|
|
3110
3119
|
if args.timeout == DEFAULT_CLI_TIMEOUT:
|
|
3111
3120
|
args.timeout = DEFAULT_TIMEOUT
|
|
3121
|
+
|
|
3122
|
+
_encoding = args.encoding
|
|
3112
3123
|
|
|
3113
3124
|
if not __global_suppress_printout:
|
|
3114
3125
|
cmdStr = getStrCommand(args.hosts,args.commands,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
multiSSH3.py,sha256=5pDQ7zSeNmfzu-o081Z7VOfW_8Ke48WPHi0BxnBnHAw,149915
|
|
2
|
+
multissh3-5.75.dist-info/METADATA,sha256=1_pBC-nNbRg_aR3LFNNInE5Whrn9hBaQMhnxEkO2IOg,18093
|
|
3
|
+
multissh3-5.75.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
+
multissh3-5.75.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
+
multissh3-5.75.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
+
multissh3-5.75.dist-info/RECORD,,
|
multissh3-5.74.dist-info/RECORD
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
multiSSH3.py,sha256=h8FnoCjcZGOjyPypzJ7H4XLOhMIKU2I-kN-m6PGdjJY,149182
|
|
2
|
-
multissh3-5.74.dist-info/METADATA,sha256=ErFNVhzY6qUCJAiI2-paOpyfNiLJKJayjXCYiQRHJPg,18093
|
|
3
|
-
multissh3-5.74.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
-
multissh3-5.74.dist-info/entry_points.txt,sha256=xi2rWWNfmHx6gS8Mmx0rZL2KZz6XWBYP3DWBpWAnnZ0,143
|
|
5
|
-
multissh3-5.74.dist-info/top_level.txt,sha256=tUwttxlnpLkZorSsroIprNo41lYSxjd2ASuL8-EJIJw,10
|
|
6
|
-
multissh3-5.74.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|