Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| ArchFlow Project Scanner | |
| Run this in your project directory to generate a scan report for ArchFlow analysis. | |
| Usage: | |
| python scan_project.py | |
| Or copy this URL and run in your terminal: | |
| curl -sSL https://archflow.ai/scan.py | python3 | |
| """ | |
| import os | |
| import json | |
| import sys | |
| from pathlib import Path | |
| from typing import Dict, List, Any | |
| def scan_directory_structure(root_path: Path, max_depth: int = 3) -> Dict[str, Any]: | |
| """Scan directory structure""" | |
| structure = { | |
| "directories": [], | |
| "files": [], | |
| "total_files": 0, | |
| "total_dirs": 0 | |
| } | |
| try: | |
| for item in root_path.rglob("*"): | |
| if item.is_dir(): | |
| # Skip common ignore patterns | |
| if any(skip in str(item) for skip in [".git", "node_modules", "__pycache__", ".venv", "venv", "dist", "build"]): | |
| continue | |
| structure["directories"].append(str(item.relative_to(root_path))) | |
| structure["total_dirs"] += 1 | |
| elif item.is_file(): | |
| structure["files"].append(str(item.relative_to(root_path))) | |
| structure["total_files"] += 1 | |
| except Exception as e: | |
| structure["error"] = str(e) | |
| return structure | |
| def detect_technologies(root_path: Path) -> Dict[str, List[str]]: | |
| """Detect technologies used in the project""" | |
| techs = { | |
| "languages": [], | |
| "frameworks": [], | |
| "tools": [], | |
| "infrastructure": [] | |
| } | |
| # Check for common config files | |
| config_files = { | |
| "package.json": ("JavaScript/TypeScript", "npm"), | |
| "requirements.txt": ("Python", "pip"), | |
| "Pipfile": ("Python", "pipenv"), | |
| "pyproject.toml": ("Python", "poetry/uv"), | |
| "Cargo.toml": ("Rust", "cargo"), | |
| "go.mod": ("Go", "go modules"), | |
| "pom.xml": ("Java", "Maven"), | |
| "build.gradle": ("Java/Kotlin", "Gradle"), | |
| "Gemfile": ("Ruby", "bundler"), | |
| "composer.json": ("PHP", "composer"), | |
| "Dockerfile": ("Docker", "containerization"), | |
| "docker-compose.yml": ("Docker Compose", "orchestration"), | |
| "vercel.json": ("Vercel", "deployment"), | |
| "netlify.toml": ("Netlify", "deployment"), | |
| ".github/workflows": ("GitHub Actions", "CI/CD"), | |
| "terraform": ("Terraform", "IaC"), | |
| "kubernetes": ("Kubernetes", "orchestration"), | |
| "next.config.js": ("Next.js", "React framework"), | |
| "vite.config.js": ("Vite", "build tool"), | |
| "tsconfig.json": ("TypeScript", "language"), | |
| } | |
| for config_file, (tech, category) in config_files.items(): | |
| file_path = root_path / config_file | |
| if file_path.exists() or (root_path / config_file.split("/")[0]).is_dir(): | |
| if "language" in category.lower() or tech in ["Python", "JavaScript", "TypeScript", "Rust", "Go", "Java", "Ruby", "PHP"]: | |
| techs["languages"].append(tech) | |
| elif "framework" in category.lower() or tech in ["Next.js", "React", "Vue"]: | |
| techs["frameworks"].append(tech) | |
| elif "deploy" in category.lower() or "CI" in category: | |
| techs["infrastructure"].append(f"{tech} ({category})") | |
| else: | |
| techs["tools"].append(f"{tech} ({category})") | |
| # Remove duplicates | |
| for key in techs: | |
| techs[key] = list(set(techs[key])) | |
| return techs | |
| def analyze_package_json(root_path: Path) -> Dict[str, Any]: | |
| """Analyze package.json for JavaScript/TypeScript projects""" | |
| package_json = root_path / "package.json" | |
| if not package_json.exists(): | |
| return {} | |
| try: | |
| with open(package_json) as f: | |
| data = json.load(f) | |
| return { | |
| "dependencies": len(data.get("dependencies", {})), | |
| "devDependencies": len(data.get("devDependencies", {})), | |
| "scripts": list(data.get("scripts", {}).keys()), | |
| "name": data.get("name", "unknown"), | |
| } | |
| except Exception as e: | |
| return {"error": str(e)} | |
| def analyze_requirements(root_path: Path) -> Dict[str, Any]: | |
| """Analyze requirements.txt for Python projects""" | |
| req_file = root_path / "requirements.txt" | |
| if not req_file.exists(): | |
| return {} | |
| try: | |
| with open(req_file) as f: | |
| requirements = [line.strip() for line in f if line.strip() and not line.startswith("#")] | |
| return { | |
| "total_dependencies": len(requirements), | |
| "dependencies": requirements[:10] # First 10 | |
| } | |
| except Exception as e: | |
| return {"error": str(e)} | |
| def generate_report(root_path: Path) -> str: | |
| """Generate the full scan report""" | |
| report_lines = [ | |
| "=" * 60, | |
| "ARCHFLOW PROJECT SCAN REPORT", | |
| "=" * 60, | |
| "", | |
| f"π Project Path: {root_path.absolute()}", | |
| f"π Scanned: {os.path.basename(root_path)}", | |
| "", | |
| "π DIRECTORY STRUCTURE", | |
| "-" * 60, | |
| ] | |
| # Directory structure | |
| structure = scan_directory_structure(root_path) | |
| report_lines.append(f"Total Directories: {structure['total_dirs']}") | |
| report_lines.append(f"Total Files: {structure['total_files']}") | |
| report_lines.append("") | |
| # Technologies | |
| report_lines.append("π οΈ DETECTED TECHNOLOGIES") | |
| report_lines.append("-" * 60) | |
| techs = detect_technologies(root_path) | |
| if techs["languages"]: | |
| report_lines.append(f"Languages: {', '.join(techs['languages'])}") | |
| if techs["frameworks"]: | |
| report_lines.append(f"Frameworks: {', '.join(techs['frameworks'])}") | |
| if techs["tools"]: | |
| report_lines.append(f"Tools: {', '.join(techs['tools'])}") | |
| if techs["infrastructure"]: | |
| report_lines.append(f"Infrastructure: {', '.join(techs['infrastructure'])}") | |
| report_lines.append("") | |
| # Package analysis | |
| pkg_data = analyze_package_json(root_path) | |
| if pkg_data: | |
| report_lines.append("π¦ PACKAGE.JSON ANALYSIS") | |
| report_lines.append("-" * 60) | |
| report_lines.append(f"Project Name: {pkg_data.get('name', 'N/A')}") | |
| report_lines.append(f"Dependencies: {pkg_data.get('dependencies', 0)}") | |
| report_lines.append(f"Dev Dependencies: {pkg_data.get('devDependencies', 0)}") | |
| report_lines.append(f"Scripts: {', '.join(pkg_data.get('scripts', []))}") | |
| report_lines.append("") | |
| # Python requirements | |
| req_data = analyze_requirements(root_path) | |
| if req_data: | |
| report_lines.append("π PYTHON DEPENDENCIES") | |
| report_lines.append("-" * 60) | |
| report_lines.append(f"Total: {req_data.get('total_dependencies', 0)}") | |
| if "dependencies" in req_data: | |
| report_lines.append("Top dependencies:") | |
| for dep in req_data["dependencies"]: | |
| report_lines.append(f" - {dep}") | |
| report_lines.append("") | |
| # Complexity warnings | |
| report_lines.append("β οΈ COMPLEXITY INDICATORS") | |
| report_lines.append("-" * 60) | |
| warnings = [] | |
| if "Kubernetes" in str(techs["infrastructure"]): | |
| warnings.append("π¨ Kubernetes detected - Consider if Docker Compose is sufficient") | |
| if structure["total_dirs"] > 50: | |
| warnings.append(f"π Large project ({structure['total_dirs']} directories) - Consider modularization") | |
| if pkg_data.get("dependencies", 0) > 50: | |
| warnings.append(f"π¦ Many dependencies ({pkg_data['dependencies']}) - Bundle size concern") | |
| if warnings: | |
| for warning in warnings: | |
| report_lines.append(warning) | |
| else: | |
| report_lines.append("β No obvious complexity concerns detected") | |
| report_lines.append("") | |
| report_lines.append("=" * 60) | |
| report_lines.append("Copy this entire report and paste it into ArchFlow for analysis!") | |
| report_lines.append("=" * 60) | |
| return "\n".join(report_lines) | |
| def main(): | |
| """Main execution""" | |
| import sys | |
| import io | |
| # Fix Windows encoding for emojis | |
| if sys.platform == "win32": | |
| sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') | |
| print("\nπ₯οΈ ArchFlow Project Scanner\n") | |
| # Get project path (current directory by default) | |
| if len(sys.argv) > 1: | |
| project_path = Path(sys.argv[1]) | |
| else: | |
| project_path = Path.cwd() | |
| if not project_path.exists(): | |
| print(f"β Error: Path '{project_path}' does not exist") | |
| sys.exit(1) | |
| print(f"π Scanning: {project_path.absolute()}") | |
| print("β³ Please wait...\n") | |
| report = generate_report(project_path) | |
| print(report) | |
| # Optionally save to file | |
| output_file = project_path / "archflow_scan.txt" | |
| try: | |
| with open(output_file, "w", encoding="utf-8") as f: | |
| f.write(report) | |
| print(f"\nπΎ Report saved to: {output_file}") | |
| except Exception as e: | |
| print(f"\nβ οΈ Could not save report: {e}") | |
| if __name__ == "__main__": | |
| main() | |