multiSSH3 5.96__tar.gz → 5.97__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.
- {multissh3-5.96 → multissh3-5.97}/PKG-INFO +1 -1
- {multissh3-5.96 → multissh3-5.97}/README.md +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/PKG-INFO +1 -1
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.py +43 -6
- {multissh3-5.96 → multissh3-5.97}/setup.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/test/test.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/test/testCurses.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/test/testCursesOld.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/test/testPerfCompact.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/test/testPerfExpand.py +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/SOURCES.txt +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/requires.txt +0 -0
- {multissh3-5.96 → multissh3-5.97}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-5.96 → multissh3-5.97}/setup.cfg +0 -0
|
File without changes
|
|
@@ -84,7 +84,7 @@ except Exception:
|
|
|
84
84
|
print('Warning: functools.lru_cache is not available, multiSSH3 will run slower without cache.',file=sys.stderr)
|
|
85
85
|
def cache_decorator(func):
|
|
86
86
|
return func
|
|
87
|
-
version = '5.
|
|
87
|
+
version = '5.97'
|
|
88
88
|
VERSION = version
|
|
89
89
|
__version__ = version
|
|
90
90
|
COMMIT_DATE = '2025-10-21'
|
|
@@ -420,6 +420,11 @@ __thread_start_delay = 0
|
|
|
420
420
|
_encoding = DEFAULT_ENCODING
|
|
421
421
|
__returnZero = DEFAULT_RETURN_ZERO
|
|
422
422
|
__running_threads = set()
|
|
423
|
+
__control_master_string = '''Host *
|
|
424
|
+
ControlMaster auto
|
|
425
|
+
ControlPath /run/user/%i/ssh_sockets_%C
|
|
426
|
+
ControlPersist 3600
|
|
427
|
+
'''
|
|
423
428
|
if __resource_lib_available:
|
|
424
429
|
# Get the current limits
|
|
425
430
|
_, __system_nofile_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
|
|
@@ -1388,14 +1393,14 @@ def compact_hostnames(Hostnames,verify = True):
|
|
|
1388
1393
|
# hostSet = frozenset(Hostnames)
|
|
1389
1394
|
# else:
|
|
1390
1395
|
# hostSet = Hostnames
|
|
1391
|
-
hostSet = frozenset(
|
|
1396
|
+
hostSet = frozenset(expand_hostnames(
|
|
1392
1397
|
hostname.strip()
|
|
1393
1398
|
for hostnames_str in Hostnames
|
|
1394
1399
|
for hostname in hostnames_str.split(',')
|
|
1395
|
-
)
|
|
1400
|
+
))
|
|
1396
1401
|
compact_hosts = __compact_hostnames(hostSet)
|
|
1397
1402
|
if verify:
|
|
1398
|
-
if
|
|
1403
|
+
if frozenset(expand_hostnames(compact_hosts)) != hostSet:
|
|
1399
1404
|
if not __global_suppress_printout:
|
|
1400
1405
|
eprint(f"Error compacting hostnames: {hostSet} -> {compact_hosts}")
|
|
1401
1406
|
compact_hosts = hostSet
|
|
@@ -2918,7 +2923,7 @@ def pre_merge_hosts(hosts):
|
|
|
2918
2923
|
# Create merged hosts
|
|
2919
2924
|
merged_hosts = []
|
|
2920
2925
|
for group in output_groups.values():
|
|
2921
|
-
group[0].name = ','.join(host.name for host in group)
|
|
2926
|
+
group[0].name = ','.join(compact_hostnames(host.name for host in group))
|
|
2922
2927
|
merged_hosts.append(group[0])
|
|
2923
2928
|
return merged_hosts
|
|
2924
2929
|
|
|
@@ -2931,6 +2936,7 @@ def get_host_raw_output(hosts, terminal_width):
|
|
|
2931
2936
|
max_length = 20
|
|
2932
2937
|
hosts = pre_merge_hosts(hosts)
|
|
2933
2938
|
for host in hosts:
|
|
2939
|
+
max_length = max(max_length, len(max(host.name.split(','), key=len)) + 3)
|
|
2934
2940
|
hostPrintOut = ["│█ EXECUTED COMMAND:"]
|
|
2935
2941
|
for line in host.command.splitlines():
|
|
2936
2942
|
hostPrintOut.extend(text_wrapper.wrap(line))
|
|
@@ -3800,6 +3806,7 @@ def get_parser():
|
|
|
3800
3806
|
parser.add_argument('-e','--encoding', type=str, help=f'The encoding to use for the output. (default: {DEFAULT_ENCODING})', default=DEFAULT_ENCODING)
|
|
3801
3807
|
parser.add_argument('-dt','--diff_display_threshold', type=float, help=f'The threshold of lines to display the diff when files differ. {{0-1}} Set to 0 to always display the diff. Set to 1 to disable diff. (Only merge same) (default: {DEFAULT_DIFF_DISPLAY_THRESHOLD})', default=DEFAULT_DIFF_DISPLAY_THRESHOLD)
|
|
3802
3808
|
parser.add_argument('--force_truecolor', action='store_true', help=f'Force truecolor output even when not in a truecolor terminal. (default: {FORCE_TRUECOLOR})', default=FORCE_TRUECOLOR)
|
|
3809
|
+
parser.add_argument('--add_control_master_config', action='store_true', help='Add ControlMaster configuration to ~/.ssh/config to speed up multiple connections to the same host.')
|
|
3803
3810
|
parser.add_argument("-V","--version", action='version', version=f'%(prog)s {version} @ {COMMIT_DATE} with [ {", ".join(_binPaths.keys())} ] by {AUTHOR} ({AUTHOR_EMAIL})')
|
|
3804
3811
|
return parser
|
|
3805
3812
|
|
|
@@ -3859,7 +3866,7 @@ def process_config_file(args):
|
|
|
3859
3866
|
else:
|
|
3860
3867
|
configFileToWriteTo = args.config_file
|
|
3861
3868
|
write_default_config(args,configFileToWriteTo)
|
|
3862
|
-
if not args.commands:
|
|
3869
|
+
if not args.commands and not args.file:
|
|
3863
3870
|
if configFileToWriteTo:
|
|
3864
3871
|
with open(configFileToWriteTo,'r') as f:
|
|
3865
3872
|
eprint(f"Config file content: \n{f.read()}")
|
|
@@ -3901,6 +3908,35 @@ def process_keys(args):
|
|
|
3901
3908
|
eprint(f"Warning: Identity file {args.key!r} not found. Passing to ssh anyway. Proceed with caution.")
|
|
3902
3909
|
return args
|
|
3903
3910
|
|
|
3911
|
+
def process_control_master_config(args):
|
|
3912
|
+
global __control_master_string
|
|
3913
|
+
if args.add_control_master_config:
|
|
3914
|
+
try:
|
|
3915
|
+
if not os.path.exists(os.path.expanduser('~/.ssh')):
|
|
3916
|
+
os.makedirs(os.path.expanduser('~/.ssh'),mode=0o700)
|
|
3917
|
+
ssh_config_file = os.path.expanduser('~/.ssh/config')
|
|
3918
|
+
if not os.path.exists(ssh_config_file):
|
|
3919
|
+
with open(ssh_config_file,'w') as f:
|
|
3920
|
+
f.write(__control_master_string)
|
|
3921
|
+
os.chmod(ssh_config_file,0o644)
|
|
3922
|
+
else:
|
|
3923
|
+
with open(ssh_config_file,'r') as f:
|
|
3924
|
+
ssh_config_content = f.readlines()
|
|
3925
|
+
if set(map(str.strip,ssh_config_content)).issuperset(set(map(str.strip,__control_master_string.splitlines()))):
|
|
3926
|
+
eprint("ControlMaster configuration already exists in ~/.ssh/config, skipping adding:")
|
|
3927
|
+
eprint(__control_master_string)
|
|
3928
|
+
else:
|
|
3929
|
+
with open(ssh_config_file,'a') as f:
|
|
3930
|
+
f.write('\n# Added by multiSSH3.py to speed up subsequent connections\n')
|
|
3931
|
+
f.write(__control_master_string)
|
|
3932
|
+
eprint("ControlMaster configuration added to ~/.ssh/config.")
|
|
3933
|
+
except Exception as e:
|
|
3934
|
+
eprint(f"Error adding ControlMaster configuration: {e}")
|
|
3935
|
+
import traceback
|
|
3936
|
+
traceback.print_exc()
|
|
3937
|
+
if not args.commands and not args.file:
|
|
3938
|
+
_exit_with_code(0, "Done configuring ControlMaster.")
|
|
3939
|
+
return args
|
|
3904
3940
|
|
|
3905
3941
|
def set_global_with_args(args):
|
|
3906
3942
|
global _emo
|
|
@@ -3937,6 +3973,7 @@ def main():
|
|
|
3937
3973
|
args = process_config_file(args)
|
|
3938
3974
|
args = process_commands(args)
|
|
3939
3975
|
args = process_keys(args)
|
|
3976
|
+
args = process_control_master_config(args)
|
|
3940
3977
|
set_global_with_args(args)
|
|
3941
3978
|
|
|
3942
3979
|
if args.use_script_timeout:
|
|
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
|