1#!/usr/bin/env python32import glob3from pathlib import Path4from argparse import ArgumentParser5import subprocess67current_template = {8 "host": "",9 "hostname": "",10 "port": "22",11 "user": "",12 "tags": [],13 "group": "default"14}1516pathes = ["~/.ssh/config"]1718def main():19 parser = ArgumentParser("sshhosts")20 parser.add_argument("-s", "--script", action='store_true', help="write script frendly output")21 args = parser.parse_args()2223 global pathes24 hosts = dict()2526 while len(pathes) != 0:27 path, pathes = pathes[0], pathes[1:]28 with Path(path).expanduser().open() as f:29 newhosts = sshhosts(f)30 for g, h in newhosts.items():31 if hosts.get(g) is None:32 hosts[g] = list()33 hosts[g] += h3435 output(hosts, script=args.script)363738def sshhosts(sshfile) -> dict[str, list[dict[str, any]]]:39 result = dict()40 current = current_template.copy()4142 for line in sshfile:43 if len(line.strip()) == 0:44 continue4546 line = line.strip().lower()47 if line.startswith("host "):4849 if current["host"] != "":50 if result.get(current["group"]) is None:51 result[current["group"]] = list()52 result[current["group"]].append(current)5354 current = current_template.copy()5556 parts = line.split("#", 1)57 if len(parts) == 1:58 comment = ""59 line = parts[0]60 else:61 (line, comment) = parts6263 options = comment.split(";")64 options = [i.strip() for i in options]65 if "hiden" in options:66 continue67 for opt in options:68 if opt.startswith("group:"):69 current["group"] = opt[len("group:"):].strip()70 if opt.startswith("tags:"):71 current["tags"] = [i.strip() for i in opt[len("tags:"):].strip().split(",")]7273 current["host"] = line[len("host "):]7475 elif line.startswith("hostname "):76 current["hostname"] = line[len("hostname "):]77 elif line.startswith("port "):78 current["port"] = line[len("port "):]79 elif line.startswith("user "):80 current["user"] = line[len("user "):]81 elif line.startswith("include "):82 global pathes83 pathes += (glob.glob(str(Path(line[len("include "):]).expanduser())))8485 if current["host"] != "":86 if result.get(current["group"]) is None:87 result[current["group"]] = list()8889 result[current["group"]].append(current)9091 return result9293def output(hosts:dict[str, list[dict[str, any]]], script:bool = False):94 if script is False:95 for group, hosts in hosts.items():96 print(f"+ {group}")97 for host in hosts:98 prefix = f"{host['host']:15} {host['hostname']}:{host['port']}"99 prefix = f"{prefix:50} {'@' + host['user']if host['user'] else ''}"100 if len(host['tags']) != 0:101 prefix = f"{prefix:60} {','.join(['#'+i for i in host['tags']])}"102 print(prefix)103 print("")104105 else:106 for group, hosts in hosts.items():107 for host in hosts:108 prefix = f"{host['host'].strip():15} {host['hostname']}:{host['port']}{' @' + host['user']if host['user'] else ''} +{group}"109 if len(host['tags']) != 0:110 prefix = f"{prefix} {','.join(['#'+i for i in host['tags']])}"111 print(prefix)112113114115116if __name__ == "__main__":117 main()