import os from collections import OrderedDict class Colors: GREEN = "\033[0;32m" RED = "\033[0;31m" YELLOW = "\033[1;33m" CYAN = "\033[0;36m" BOLD = "\033[1m" RESET = "\033[0m" def print_error(message): print(f"{Colors.RED}{Colors.BOLD}[✖] {Colors.RESET}{message}") def print_warning(message): print(f"{Colors.YELLOW}{Colors.BOLD}[⚠] {Colors.RESET}{message}") def print_info(message): print(f"{Colors.GREEN}{Colors.BOLD}[✔] {Colors.RESET}{message}") def load_config_file(file_path): """ Parse a single SSH config file and return a list of host blocks. Each block is an OrderedDict with keys like 'Host', 'HostName', etc. """ blocks = [] host_data = None try: with open(file_path, 'r') as f: lines = f.readlines() except Exception as e: print_error(f"Error reading SSH config file {file_path}: {e}") return blocks for line in lines: stripped_line = line.strip() # Skip empty lines and comments if not stripped_line or stripped_line.startswith('#'): continue # Start of a new Host block if stripped_line.lower().startswith('host '): host_labels = stripped_line.split()[1:] # Pick the first label that isn't a wildcard for label in host_labels: if '*' not in label: # If we already have a host_data in progress, close it out if host_data: blocks.append(host_data) host_data = OrderedDict({'Host': label}) break elif host_data: # Split on the first whitespace into key/value if ' ' in stripped_line: key, value = stripped_line.split(None, 1) host_data[key] = value.strip() # Add the last block if it exists if host_data: blocks.append(host_data) return blocks def edit_host(CONF_DIR): """ Let the user update fields for an existing host. 1) Ask which host label to edit 2) Locate its subdirectory + config 3) Update (HostName, User, Port, IdentityFile) as needed 4) Rewrite the config """ host_label = input("Enter the Host label to edit: ").strip() if not host_label: print_error("Host label cannot be empty.") return host_dir = os.path.join(CONF_DIR, host_label) config_path = os.path.join(host_dir, "config") if not os.path.isfile(config_path): print_warning(f"No config file found at {config_path}; cannot edit this host.") return # Load the config file and look for the relevant host block blocks = load_config_file(config_path) if not blocks: print_warning(f"No valid Host blocks found in {config_path}") return # We'll assume there's only one block in each config # (the "Host