Refactor code structure and optimize performance across multiple modules

This commit is contained in:
StellaOps Bot
2025-12-26 20:03:22 +02:00
parent c786faae84
commit b4fc66feb6
3353 changed files with 88254 additions and 1590657 deletions

380
generate_solutions.py Normal file
View File

@@ -0,0 +1,380 @@
#!/usr/bin/env python3
"""
Generate Visual Studio solution files for StellaOps
Organizes all .csproj files into:
1. Main StellaOps.sln (all projects)
2. Module-specific .sln files
3. StellaOps.Infrastructure.sln (shared libraries)
4. StellaOps.Tests.sln (global tests)
"""
import os
import uuid
import re
from pathlib import Path
from typing import Dict, List, Set, Tuple
from collections import defaultdict
# Base directory
BASE_DIR = Path(r"E:\dev\git.stella-ops.org")
SRC_DIR = BASE_DIR / "src"
# Module names based on directory structure
MODULES = [
"AdvisoryAI", "AirGap", "Aoc", "Attestor", "Authority", "Bench",
"BinaryIndex", "Cartographer", "Cli", "Concelier", "Cryptography",
"EvidenceLocker", "Excititor", "ExportCenter", "Gateway", "Graph",
"IssuerDirectory", "Notify", "Orchestrator", "Policy", "Replay",
"SbomService", "Scanner", "Scheduler", "Signer", "Signals",
"TaskRunner", "Telemetry", "VexHub", "VexLens", "VulnExplorer",
"Web", "Zastava"
]
# Project type GUIDs
FAE04EC0_301F_11D3_BF4B_00C04F79EFBC = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" # C# project
SLN_FOLDER_GUID = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" # Solution folder
def generate_project_guid(project_path: str) -> str:
"""Generate deterministic GUID based on project path"""
# Use namespace UUID for deterministic generation
namespace = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
return str(uuid.uuid5(namespace, project_path)).upper()
def get_module_from_path(project_path: Path) -> str:
"""Determine module name from project path"""
relative = project_path.relative_to(SRC_DIR)
parts = relative.parts
# Check direct module directory
if len(parts) > 0 and parts[0] in MODULES:
return parts[0]
# Check __Libraries/StellaOps.<Module>.*
if parts[0] == "__Libraries":
project_name = parts[-1].replace(".csproj", "")
for module in MODULES:
if f"StellaOps.{module}" in project_name:
return module
# Check __Tests/StellaOps.<Module>.*.Tests
if parts[0] == "__Tests":
project_name = parts[-1].replace(".csproj", "")
for module in MODULES:
if f"StellaOps.{module}" in project_name:
return module
# Global tests
return "Tests"
# Check Integration tests
if len(parts) > 1 and parts[0] == "__Tests" and parts[1] == "Integration":
project_name = parts[-1].replace(".csproj", "")
for module in MODULES:
if f"StellaOps.{module}" in project_name:
return module
return "Tests"
# Default to Infrastructure for shared libraries
if parts[0] == "__Libraries":
return "Infrastructure"
return "Infrastructure"
def find_all_projects() -> List[Path]:
"""Find all .csproj files in src directory"""
projects = []
for root, dirs, files in os.walk(SRC_DIR):
for file in files:
if file.endswith(".csproj"):
projects.append(Path(root) / file)
return sorted(projects)
def categorize_project(project_path: Path, module: str) -> str:
"""Determine category for solution folder organization"""
relative = project_path.relative_to(SRC_DIR)
parts = relative.parts
# Test projects
if "__Tests" in parts or project_path.name.endswith(".Tests.csproj"):
return "Tests"
# Benchmark projects
if "Bench" in parts or "Benchmark" in project_path.name:
return "Benchmarks"
# Plugin projects
if "Plugin" in project_path.name or "Connector" in project_path.name:
return "Plugins"
# Library projects
if "__Libraries" in parts:
return "Libraries"
# Analyzer projects
if "__Analyzers" in parts or "Analyzer" in project_path.name:
return "Analyzers"
# Web services
if "WebService" in project_path.name:
return "WebServices"
# Workers
if "Worker" in project_path.name:
return "Workers"
# Core module projects
return "Core"
def generate_sln_header() -> str:
"""Generate Visual Studio 2022 solution header"""
return """Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
"""
def generate_project_entry(project_path: Path, project_guid: str) -> str:
"""Generate project entry for .sln file"""
project_name = project_path.stem
relative_path = project_path.relative_to(BASE_DIR)
return f'Project("{FAE04EC0_301F_11D3_BF4B_00C04F79EFBC}") = "{project_name}", "{relative_path}", "{{{project_guid}}}"\nEndProject'
def generate_folder_entry(folder_name: str, folder_guid: str) -> str:
"""Generate solution folder entry"""
return f'Project("{SLN_FOLDER_GUID}") = "{folder_name}", "{folder_name}", "{{{folder_guid}}}"\nEndProject'
def generate_nested_projects(folder_mappings: Dict[str, List[str]]) -> str:
"""Generate NestedProjects section"""
lines = ["\tGlobalSection(NestedProjects) = preSolution"]
for folder_guid, project_guids in folder_mappings.items():
for project_guid in project_guids:
lines.append(f"\t\t{{{project_guid}}} = {{{folder_guid}}}")
lines.append("\tEndGlobalSection")
return "\n".join(lines)
def generate_main_solution(projects: List[Path], module_assignments: Dict[str, List[Path]]) -> str:
"""Generate main StellaOps.sln with all projects"""
content = [generate_sln_header()]
# Track GUIDs
project_guids: Dict[str, str] = {}
folder_guids: Dict[str, str] = {}
folder_mappings: Dict[str, List[str]] = defaultdict(list)
# Create folder structure: Module -> Category -> Projects
for module in sorted(module_assignments.keys()):
module_folder_guid = generate_project_guid(f"folder_{module}")
folder_guids[module] = module_folder_guid
content.append(generate_folder_entry(module, module_folder_guid))
# Group projects by category within module
category_projects: Dict[str, List[Path]] = defaultdict(list)
for project in module_assignments[module]:
category = categorize_project(project, module)
category_projects[category].append(project)
# Create category folders
for category in sorted(category_projects.keys()):
category_folder_name = f"{module}.{category}"
category_folder_guid = generate_project_guid(f"folder_{category_folder_name}")
folder_guids[category_folder_name] = category_folder_guid
content.append(generate_folder_entry(category, category_folder_guid))
folder_mappings[module_folder_guid].append(category_folder_guid)
# Add projects to category
for project in sorted(category_projects[category]):
project_guid = generate_project_guid(str(project))
project_guids[str(project)] = project_guid
content.append(generate_project_entry(project, project_guid))
folder_mappings[category_folder_guid].append(project_guid)
# Add Global section
content.append("Global")
content.append("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution")
content.append("\t\tDebug|Any CPU = Debug|Any CPU")
content.append("\t\tRelease|Any CPU = Release|Any CPU")
content.append("\tEndGlobalSection")
# Project configurations
content.append("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution")
for project_guid in project_guids.values():
content.append(f"\t\t{{{project_guid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Debug|Any CPU.Build.0 = Debug|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Release|Any CPU.ActiveCfg = Release|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Release|Any CPU.Build.0 = Release|Any CPU")
content.append("\tEndGlobalSection")
# Nested projects
content.append(generate_nested_projects(folder_mappings))
content.append("EndGlobal")
return "\n".join(content)
def generate_module_solution(module: str, projects: List[Path]) -> str:
"""Generate module-specific .sln file"""
content = [generate_sln_header()]
project_guids: Dict[str, str] = {}
folder_guids: Dict[str, str] = {}
folder_mappings: Dict[str, List[str]] = defaultdict(list)
# Group projects by category
category_projects: Dict[str, List[Path]] = defaultdict(list)
for project in projects:
category = categorize_project(project, module)
category_projects[category].append(project)
# Create category folders and add projects
for category in sorted(category_projects.keys()):
category_folder_guid = generate_project_guid(f"folder_{module}_{category}")
folder_guids[category] = category_folder_guid
content.append(generate_folder_entry(category, category_folder_guid))
for project in sorted(category_projects[category]):
project_guid = generate_project_guid(str(project))
project_guids[str(project)] = project_guid
content.append(generate_project_entry(project, project_guid))
folder_mappings[category_folder_guid].append(project_guid)
# Add Global section
content.append("Global")
content.append("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution")
content.append("\t\tDebug|Any CPU = Debug|Any CPU")
content.append("\t\tRelease|Any CPU = Release|Any CPU")
content.append("\tEndGlobalSection")
# Project configurations
content.append("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution")
for project_guid in project_guids.values():
content.append(f"\t\t{{{project_guid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Debug|Any CPU.Build.0 = Debug|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Release|Any CPU.ActiveCfg = Release|Any CPU")
content.append(f"\t\t{{{project_guid}}}.Release|Any CPU.Build.0 = Release|Any CPU")
content.append("\tEndGlobalSection")
# Nested projects
content.append(generate_nested_projects(folder_mappings))
content.append("EndGlobal")
return "\n".join(content)
def main():
print("Finding all .csproj files...")
all_projects = find_all_projects()
print(f"Found {len(all_projects)} projects")
# Assign projects to modules
module_assignments: Dict[str, List[Path]] = defaultdict(list)
for project in all_projects:
module = get_module_from_path(project)
module_assignments[module].append(project)
# Print summary
print("\nModule assignment summary:")
for module in sorted(module_assignments.keys()):
print(f" {module}: {len(module_assignments[module])} projects")
# Generate main solution
print("\nGenerating main StellaOps.sln...")
main_sln = generate_main_solution(all_projects, module_assignments)
main_sln_path = SRC_DIR / "StellaOps.sln"
with open(main_sln_path, 'w', encoding='utf-8-sig') as f:
f.write(main_sln)
print(f" Written: {main_sln_path}")
print(f" Projects: {len(all_projects)}")
# Generate module-specific solutions
print("\nGenerating module-specific solutions...")
for module in sorted(module_assignments.keys()):
if module in ["Infrastructure", "Tests"]:
# These get special handling below
continue
projects = module_assignments[module]
if len(projects) == 0:
continue
module_sln = generate_module_solution(module, projects)
module_sln_path = SRC_DIR / f"StellaOps.{module}.sln"
with open(module_sln_path, 'w', encoding='utf-8-sig') as f:
f.write(module_sln)
print(f" Written: {module_sln_path}")
print(f" Projects: {len(projects)}")
# Generate Infrastructure solution
if "Infrastructure" in module_assignments:
print("\nGenerating StellaOps.Infrastructure.sln...")
infra_projects = module_assignments["Infrastructure"]
infra_sln = generate_module_solution("Infrastructure", infra_projects)
infra_sln_path = SRC_DIR / "StellaOps.Infrastructure.sln"
with open(infra_sln_path, 'w', encoding='utf-8-sig') as f:
f.write(infra_sln)
print(f" Written: {infra_sln_path}")
print(f" Projects: {len(infra_projects)}")
# Generate Tests solution
if "Tests" in module_assignments:
print("\nGenerating StellaOps.Tests.sln...")
test_projects = module_assignments["Tests"]
test_sln = generate_module_solution("Tests", test_projects)
test_sln_path = SRC_DIR / "StellaOps.Tests.sln"
with open(test_sln_path, 'w', encoding='utf-8-sig') as f:
f.write(test_sln)
print(f" Written: {test_sln_path}")
print(f" Projects: {len(test_projects)}")
# Verify each project is in exactly 2 solutions
print("\n\nVerifying project membership...")
project_solution_count: Dict[str, Set[str]] = defaultdict(set)
# Count main solution
for project in all_projects:
project_solution_count[str(project)].add("StellaOps.sln")
# Count module solutions
for module, projects in module_assignments.items():
if module == "Infrastructure":
sln_name = "StellaOps.Infrastructure.sln"
elif module == "Tests":
sln_name = "StellaOps.Tests.sln"
else:
sln_name = f"StellaOps.{module}.sln"
for project in projects:
project_solution_count[str(project)].add(sln_name)
# Check for violations
violations = []
for project, solutions in project_solution_count.items():
if len(solutions) != 2:
violations.append((project, solutions))
if violations:
print(f"\n❌ ERROR: {len(violations)} projects are not in exactly 2 solutions:")
for project, solutions in violations[:10]: # Show first 10
print(f" {Path(project).name}: in {len(solutions)} solutions - {solutions}")
if len(violations) > 10:
print(f" ... and {len(violations) - 10} more")
else:
print("✅ All projects are in exactly 2 solutions!")
print("\n✅ Solution generation complete!")
print(f" Total projects: {len(all_projects)}")
print(f" Solutions created: {len(module_assignments) + 1}")
if __name__ == "__main__":
main()