Universal-AI-Hub / .github /scripts /generate_structure.py
Alibrown's picture
Upload 58 files
5ef3828 verified
Raw History Blame Contribute Delete
3.37 kB
#!/usr/bin/env python3
# =============================================================================
# generate_structure.py
# Generates PROJECT_STRUCTURE.md with a visual repo tree.
# Place in: .codey/scripts/generate_structure.py
# =============================================================================
# PYTHON VERSION NOTE:
# Embedding \n inside f-string expressions like f"{'\n'.join(x)}" is only
# supported from Python 3.12+. On 3.10/3.11 (GitHub Actions default) this
# causes a SyntaxError: "unterminated string literal".
# FIX: always build the joined string BEFORE the f-string block.
# Example:
# BAD β†’ f"```\n{'\n'.join(tree)}\n```" # crashes on 3.10/3.11
# GOOD β†’ tree_str = "\n".join(tree)
# then use tree_str inside f-string or concatenation
# =============================================================================
from pathlib import Path
from datetime import datetime
# ─────────────────────────────────────────────
# IGNORE LIST β€” folders/files to skip
# ─────────────────────────────────────────────
IGNORE = {
'.git',
'__pycache__',
'.pytest_cache',
'*.pyc',
'.DS_Store',
'node_modules',
'.venv',
'venv',
}
def is_ignored(path: Path) -> bool:
name = path.name
for pattern in IGNORE:
if '*' in pattern:
if path.match(pattern):
return True
elif name == pattern:
return True
return False
def generate_tree(root: Path, prefix: str = "", is_last: bool = True) -> list:
lines = []
connector = "└── " if is_last else "β”œβ”€β”€ "
if root == Path("."):
lines.append(root.resolve().name + "/")
children = sorted(root.iterdir(), key=lambda p: (p.is_file(), p.name.lower()))
visible = [c for c in children if not is_ignored(c)]
for i, child in enumerate(visible):
lines.extend(generate_tree(child, prefix="", is_last=(i == len(visible) - 1)))
return lines
if root.is_dir():
lines.append(f"{prefix}{connector}{root.name}/")
extension = " " if is_last else "β”‚ "
children = sorted(root.iterdir(), key=lambda p: (p.is_file(), p.name.lower()))
visible = [c for c in children if not is_ignored(c)]
for i, child in enumerate(visible):
lines.extend(generate_tree(child, prefix + extension, is_last=(i == len(visible) - 1)))
else:
lines.append(f"{prefix}{connector}{root.name}")
return lines
def main():
root = Path(".")
tree = generate_tree(root)
now = datetime.utcnow().strftime("%Y-%m-%d %H:%M UTC")
# Build tree string BEFORE f-string β€” required for Python < 3.12
tree_str = "\n".join(tree)
output = "# πŸ“ Project Structure\n\n"
output += f"> Auto-generated by `generate_structure.py` β€” {now}\n"
output += "> Do not edit manually.\n\n"
output += "```\n"
output += tree_str + "\n"
output += "```\n"
out_path = Path("PROJECT_STRUCTURE.md")
out_path.write_text(output, encoding="utf-8")
print(f"βœ“ PROJECT_STRUCTURE.md written ({len(tree)} lines)")
if __name__ == "__main__":
main()