124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
import os
|
|
import asyncio
|
|
from collections import OrderedDict
|
|
from .utils import print_error, print_warning, print_info, safe_input
|
|
from .list_hosts import (
|
|
build_host_list_table,
|
|
load_config_file,
|
|
gather_host_info,
|
|
sort_by_ip
|
|
)
|
|
|
|
async def edit_host(conf_dir):
|
|
"""
|
|
Let the user update fields for an existing host in ~/.ssh/conf/<label>/config.
|
|
1) Display the unified table (No. | Host | User | Port | HostName | IP Address | Conf Directory)
|
|
2) Prompt row number or host label
|
|
3) Rewrite config with updated fields
|
|
"""
|
|
|
|
print_info("Here is the current list of hosts:\n")
|
|
headers, final_data = await build_host_list_table(conf_dir)
|
|
if not final_data:
|
|
print_warning("No hosts to edit.")
|
|
return
|
|
|
|
from tabulate import tabulate
|
|
print("\nSSH Conf Subdirectory Host List (Sorted by IP Ascending)")
|
|
print(tabulate(final_data, headers=headers, tablefmt="grid"))
|
|
|
|
choice = safe_input("Enter the row number or the Host label to edit: ")
|
|
if choice is None:
|
|
return # user canceled (Ctrl+C)
|
|
choice = choice.strip()
|
|
if not choice:
|
|
print_error("Host label or row number cannot be empty.")
|
|
return
|
|
|
|
# We replicate the approach to find the matching block
|
|
all_blocks = []
|
|
import glob
|
|
for cfile in glob.glob(os.path.join(conf_dir, "*", "config")):
|
|
all_blocks.extend(load_config_file(cfile))
|
|
|
|
results = await gather_host_info(all_blocks)
|
|
sorted_rows = sort_by_ip(results)
|
|
|
|
target_tuple = None
|
|
if choice.isdigit():
|
|
idx = int(choice)
|
|
if idx < 1 or idx > len(sorted_rows):
|
|
print_warning(f"Row number {idx} is invalid.")
|
|
return
|
|
target_tuple = sorted_rows[idx - 1]
|
|
else:
|
|
for t in sorted_rows:
|
|
if t[0] == choice: # t[0] => host_label
|
|
target_tuple = t
|
|
break
|
|
if not target_tuple:
|
|
print_warning(f"No matching Host '{choice}' found in the table.")
|
|
return
|
|
|
|
host_label = target_tuple[0]
|
|
# find the config block
|
|
found_block = None
|
|
for b in all_blocks:
|
|
if b.get("Host") == host_label:
|
|
found_block = b
|
|
break
|
|
|
|
if not found_block:
|
|
print_warning(f"No config block found for '{host_label}'.")
|
|
return
|
|
|
|
old_hostname = found_block.get("HostName", "")
|
|
old_user = found_block.get("User", "")
|
|
old_port = found_block.get("Port", "22")
|
|
old_identity = found_block.get("IdentityFile", "")
|
|
|
|
print_info("Leave a field blank to keep its current value.")
|
|
|
|
new_hostname = safe_input(f"Enter new HostName [{old_hostname}]: ")
|
|
if new_hostname is None:
|
|
return
|
|
new_hostname = new_hostname.strip()
|
|
|
|
new_user = safe_input(f"Enter new User [{old_user}]: ")
|
|
if new_user is None:
|
|
return
|
|
new_user = new_user.strip()
|
|
|
|
new_port = safe_input(f"Enter new Port [{old_port}]: ")
|
|
if new_port is None:
|
|
return
|
|
new_port = new_port.strip()
|
|
|
|
new_ident = safe_input(f"Enter new IdentityFile [{old_identity}]: ")
|
|
if new_ident is None:
|
|
return
|
|
new_ident = new_ident.strip()
|
|
|
|
final_hostname = new_hostname if new_hostname else old_hostname
|
|
final_user = new_user if new_user else old_user
|
|
final_port = new_port if new_port else old_port
|
|
final_ident = new_ident if new_ident else old_identity
|
|
|
|
# Overwrite the file
|
|
config_path = os.path.join(conf_dir, host_label, "config")
|
|
new_config_lines = [
|
|
f"Host {host_label}",
|
|
f" HostName {final_hostname}",
|
|
f" User {final_user}",
|
|
f" Port {final_port}"
|
|
]
|
|
if final_ident:
|
|
new_config_lines.append(f" IdentityFile {final_ident}")
|
|
|
|
try:
|
|
with open(config_path, "w") as f:
|
|
for line in new_config_lines:
|
|
f.write(line + "\n")
|
|
print_info(f"Updated config at: {config_path}")
|
|
except Exception as e:
|
|
print_error(f"Failed to update config: {e}")
|