import shlex def tokenize(text) -> list: lexer = shlex.shlex(text, posix=True) lexer.whitespace_split = True lexer.commenters = "#" lexer.wordchars += ".:/-@()," return list(lexer) def parse_sites_imports(text): tokens = tokenize(text) result = {} current_site = None depth = 0 i = 0 while i < len(tokens): tok = tokens[i] # detect site start if i + 1 < len(tokens) and tokens[i + 1] == "{": if depth == 0: sites = [s.strip() for s in tok.split(",")] for s in sites: result.setdefault(s, []) current_site = sites depth += 1 i += 2 continue if tok == "{": depth += 1 elif tok == "}": depth -= 1 if depth == 0: current_site = None elif tok == "import" and i + 1 < len(tokens) and current_site: name = tokens[i + 1] for site in current_site: result[site].append(name) i += 2 continue i += 1 return result def filter_globals_out(data) -> dict: import re ret = dict() for key, values in data.items(): if re.match(r"\(\w+\)", key): # exclude import definitions e.g (auth) continue ret[key] = values return ret def parse(caddy_string) -> dict[str, list[str]]: return filter_globals_out(parse_sites_imports(caddy_string)) if __name__ == "__main__": with open("Caddyfile") as f: data = parse(f.read()) print(data)