This commit is contained in:
243
src/generator.py
Normal file
243
src/generator.py
Normal file
@@ -0,0 +1,243 @@
|
||||
"""Gitignore generation from templates."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Set
|
||||
|
||||
|
||||
class GitignoreGenerator:
|
||||
"""Generate .gitignore content from templates."""
|
||||
|
||||
TEMPLATE_MAP: Dict[str, str] = {
|
||||
"python": "languages/python.gitignore",
|
||||
"javascript": "languages/javascript.gitignore",
|
||||
"typescript": "languages/typescript.gitignore",
|
||||
"java": "languages/java.gitignore",
|
||||
"go": "languages/go.gitignore",
|
||||
"rust": "languages/rust.gitignore",
|
||||
"dotnet": "languages/dotnet.gitignore",
|
||||
"php": "languages/php.gitignore",
|
||||
"ruby": "languages/ruby.gitignore",
|
||||
"django": "frameworks/django.gitignore",
|
||||
"flask": "frameworks/flask.gitignore",
|
||||
"react": "frameworks/react.gitignore",
|
||||
"vue": "frameworks/vue.gitignore",
|
||||
"angular": "frameworks/angular.gitignore",
|
||||
"rails": "frameworks/rails.gitignore",
|
||||
"laravel": "frameworks/laravel.gitignore",
|
||||
"spring": "frameworks/spring.gitignore",
|
||||
"vscode": "ide/vscode.gitignore",
|
||||
"jetbrains": "ide/jetbrains.gitignore",
|
||||
"visualstudiocode": "ide/visualstudiocode.gitignore",
|
||||
"linux": "os/linux.gitignore",
|
||||
"macos": "os/macos.gitignore",
|
||||
"windows": "os/windows.gitignore",
|
||||
"docker": "tools/docker.gitignore",
|
||||
"gradle": "tools/gradle.gitignore",
|
||||
"maven": "tools/maven.gitignore",
|
||||
"jupyter": "tools/jupyter.gitignore",
|
||||
"terraform": "tools/terraform.gitignore",
|
||||
}
|
||||
|
||||
def __init__(self, config: Optional["Config"] = None) -> None:
|
||||
"""Initialize generator with optional configuration."""
|
||||
self.template_dir = Path(__file__).parent / "templates"
|
||||
self.selected_templates: Set[str] = set()
|
||||
self.config = config
|
||||
|
||||
def add_template(self, template_type: str) -> None:
|
||||
"""Add a template type to include."""
|
||||
if template_type in self.TEMPLATE_MAP:
|
||||
self.selected_templates.add(template_type)
|
||||
|
||||
def remove_template(self, template_type: str) -> None:
|
||||
"""Remove a template type from selection."""
|
||||
self.selected_templates.discard(template_type)
|
||||
|
||||
def get_template_path(self, template_type: str) -> Optional[Path]:
|
||||
"""Get the path to a template file."""
|
||||
template_rel = self.TEMPLATE_MAP.get(template_type)
|
||||
if template_rel:
|
||||
template_path = self.template_dir / template_rel
|
||||
if template_path.exists():
|
||||
return template_path
|
||||
return None
|
||||
|
||||
def load_template(self, template_type: str) -> str:
|
||||
"""Load template content."""
|
||||
template_path = self.get_template_path(template_type)
|
||||
if template_path:
|
||||
try:
|
||||
with open(template_path, "r") as f:
|
||||
return f.read()
|
||||
except OSError:
|
||||
return ""
|
||||
return ""
|
||||
|
||||
def load_template_lines(self, template_type: str) -> List[str]:
|
||||
"""Load template content as list of lines."""
|
||||
content = self.load_template(template_type)
|
||||
lines = content.split("\n")
|
||||
while lines and not lines[-1]:
|
||||
lines.pop()
|
||||
while lines and not lines[0]:
|
||||
lines.pop(0)
|
||||
return lines
|
||||
|
||||
def deduplicate_entries(
|
||||
self, entries: List[str], comments: List[str] = None
|
||||
) -> List[str]:
|
||||
"""Remove duplicate entries while preserving order."""
|
||||
seen: Set[str] = set()
|
||||
unique_entries: List[str] = []
|
||||
for entry in entries:
|
||||
normalized = entry.strip().lower()
|
||||
if normalized and normalized not in seen:
|
||||
seen.add(normalized)
|
||||
unique_entries.append(entry)
|
||||
if comments:
|
||||
unique_comments = []
|
||||
seen_comments = set()
|
||||
for comment in comments:
|
||||
if comment not in seen_comments:
|
||||
seen_comments.add(comment)
|
||||
unique_comments.append(comment)
|
||||
return unique_comments + unique_entries
|
||||
return unique_entries
|
||||
|
||||
def generate(self) -> str:
|
||||
"""Generate combined .gitignore content."""
|
||||
all_entries: List[str] = []
|
||||
all_comments: List[str] = []
|
||||
used_categories: Set[str] = set()
|
||||
|
||||
template_order = [
|
||||
"language",
|
||||
"framework",
|
||||
"ide",
|
||||
"os",
|
||||
"tools",
|
||||
]
|
||||
|
||||
category_map = {
|
||||
"python": "language",
|
||||
"javascript": "language",
|
||||
"typescript": "language",
|
||||
"java": "language",
|
||||
"go": "language",
|
||||
"rust": "language",
|
||||
"dotnet": "language",
|
||||
"php": "language",
|
||||
"ruby": "language",
|
||||
"django": "framework",
|
||||
"flask": "framework",
|
||||
"react": "framework",
|
||||
"vue": "framework",
|
||||
"angular": "framework",
|
||||
"rails": "framework",
|
||||
"laravel": "framework",
|
||||
"spring": "framework",
|
||||
"vscode": "ide",
|
||||
"jetbrains": "ide",
|
||||
"visualstudiocode": "ide",
|
||||
"linux": "os",
|
||||
"macos": "os",
|
||||
"windows": "os",
|
||||
"docker": "tools",
|
||||
"gradle": "tools",
|
||||
"maven": "tools",
|
||||
"jupyter": "tools",
|
||||
"terraform": "tools",
|
||||
}
|
||||
|
||||
for template_type in sorted(self.selected_templates):
|
||||
template_path = self.get_template_path(template_type)
|
||||
if template_path:
|
||||
try:
|
||||
category = category_map.get(template_type, "other")
|
||||
header = f"# {template_type.upper()}"
|
||||
if header not in all_comments:
|
||||
all_comments.append(header)
|
||||
|
||||
lines = self.load_template_lines(template_type)
|
||||
all_entries.extend(lines)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if not all_entries:
|
||||
return ""
|
||||
|
||||
combined = self.deduplicate_entries(all_entries, all_comments)
|
||||
result = "\n".join(combined)
|
||||
if result and not result.endswith("\n"):
|
||||
result += "\n"
|
||||
return result
|
||||
|
||||
def generate_for_types(
|
||||
self, types: List[str], deduplicate: bool = True
|
||||
) -> str:
|
||||
"""Generate .gitignore for specific types."""
|
||||
self.selected_templates = set()
|
||||
for t in types:
|
||||
self.add_template(t)
|
||||
return self.generate()
|
||||
|
||||
def get_available_templates(self) -> List[str]:
|
||||
"""Get list of available template types."""
|
||||
available = []
|
||||
for template_type, template_rel in self.TEMPLATE_MAP.items():
|
||||
template_path = self.template_dir / template_rel
|
||||
if template_path.exists():
|
||||
available.append(template_type)
|
||||
return sorted(available)
|
||||
|
||||
def validate_template_type(self, template_type: str) -> bool:
|
||||
"""Validate if a template type is valid."""
|
||||
return template_type in self.TEMPLATE_MAP
|
||||
|
||||
def get_template_categories(self) -> Dict[str, List[str]]:
|
||||
"""Get templates organized by category."""
|
||||
categories: Dict[str, List[str]] = {
|
||||
"language": [],
|
||||
"framework": [],
|
||||
"ide": [],
|
||||
"os": [],
|
||||
"tools": [],
|
||||
}
|
||||
|
||||
category_map = {
|
||||
"python": "language",
|
||||
"javascript": "language",
|
||||
"typescript": "language",
|
||||
"java": "language",
|
||||
"go": "language",
|
||||
"rust": "language",
|
||||
"dotnet": "language",
|
||||
"php": "language",
|
||||
"ruby": "language",
|
||||
"django": "framework",
|
||||
"flask": "framework",
|
||||
"react": "framework",
|
||||
"vue": "framework",
|
||||
"angular": "framework",
|
||||
"rails": "framework",
|
||||
"laravel": "framework",
|
||||
"spring": "framework",
|
||||
"vscode": "ide",
|
||||
"jetbrains": "ide",
|
||||
"visualstudiocode": "ide",
|
||||
"linux": "os",
|
||||
"macos": "os",
|
||||
"windows": "os",
|
||||
"docker": "tools",
|
||||
"gradle": "tools",
|
||||
"maven": "tools",
|
||||
"jupyter": "tools",
|
||||
"terraform": "tools",
|
||||
}
|
||||
|
||||
for template_type in self.TEMPLATE_MAP:
|
||||
category = category_map.get(template_type, "other")
|
||||
if category in categories:
|
||||
categories[category].append(template_type)
|
||||
|
||||
return categories
|
||||
Reference in New Issue
Block a user