179 lines
6.2 KiB
Python
179 lines
6.2 KiB
Python
"""Template loader for gitignore-generator."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional, Set
|
|
|
|
from gitignore_generator.config import config
|
|
|
|
|
|
class TemplateLoader:
|
|
"""Load and manage gitignore templates."""
|
|
|
|
def __init__(self):
|
|
"""Initialize template loader."""
|
|
self._templates_index: Optional[Dict] = None
|
|
self._custom_templates: Dict[str, str] = {}
|
|
|
|
def _load_templates_index(self) -> Dict:
|
|
"""Load the templates index file."""
|
|
if self._templates_index is None:
|
|
index_path = config.template_dir / "templates.json"
|
|
if index_path.exists():
|
|
with open(index_path, "r") as f:
|
|
self._templates_index = json.load(f)
|
|
else:
|
|
self._templates_index = {"languages": [], "ides": [], "custom": []}
|
|
assert self._templates_index is not None
|
|
return self._templates_index
|
|
|
|
def _save_templates_index(self) -> None:
|
|
"""Save the templates index file."""
|
|
index_path = config.template_dir / "templates.json"
|
|
with open(index_path, "w") as f:
|
|
json.dump(self._templates_index, f, indent=2)
|
|
|
|
def get_available_templates(self, category: Optional[str] = None) -> List[str]:
|
|
"""Get list of available templates."""
|
|
index = self._load_templates_index()
|
|
self._load_custom_templates()
|
|
|
|
if category:
|
|
templates = index.get(category, [])
|
|
if category == "languages":
|
|
templates = templates + list(self._custom_templates.keys())
|
|
return sorted(set(templates))
|
|
else:
|
|
all_templates = []
|
|
for cat in ["languages", "ides"]:
|
|
all_templates.extend(index.get(cat, []))
|
|
all_templates = all_templates + list(self._custom_templates.keys())
|
|
return sorted(set(all_templates))
|
|
|
|
def get_templates_by_category(self) -> Dict[str, List[str]]:
|
|
"""Get all templates organized by category."""
|
|
index = self._load_templates_index()
|
|
self._load_custom_templates()
|
|
|
|
result = {
|
|
"languages": index.get("languages", []),
|
|
"ides": index.get("ides", []),
|
|
"custom": list(self._custom_templates.keys())
|
|
}
|
|
return result
|
|
|
|
def _load_custom_templates(self) -> None:
|
|
"""Load custom templates from user config directory."""
|
|
if self._custom_templates:
|
|
return
|
|
|
|
custom_dir = config.custom_templates_dir
|
|
if custom_dir.exists():
|
|
for template_file in custom_dir.glob("*.gitignore"):
|
|
self._custom_templates[template_file.stem] = str(template_file)
|
|
|
|
def load_template(self, template_name: str, category: Optional[str] = None) -> Optional[str]:
|
|
"""Load a template by name."""
|
|
self._load_custom_templates()
|
|
|
|
if template_name in self._custom_templates:
|
|
custom_path = Path(self._custom_templates[template_name])
|
|
if custom_path.exists():
|
|
with open(custom_path, "r") as f:
|
|
return f.read()
|
|
del self._custom_templates[template_name]
|
|
|
|
if category:
|
|
categories = [category]
|
|
else:
|
|
categories = ["languages", "ides"]
|
|
|
|
for cat in categories:
|
|
template_path = config.template_dir / cat / f"{template_name}.gitignore"
|
|
if template_path.exists():
|
|
with open(template_path, "r") as f:
|
|
return f.read()
|
|
|
|
return None
|
|
|
|
def get_template_content(self, template_name: str) -> Optional[str]:
|
|
"""Get template content by name (searches all categories)."""
|
|
return self.load_template(template_name)
|
|
|
|
def save_custom_template(self, name: str, content: str) -> bool:
|
|
"""Save a custom template."""
|
|
custom_dir = config.custom_templates_dir
|
|
try:
|
|
custom_dir.mkdir(parents=True, exist_ok=True)
|
|
except OSError:
|
|
return False
|
|
|
|
template_path = custom_dir / f"{name}.gitignore"
|
|
try:
|
|
with open(template_path, "w") as f:
|
|
f.write(content)
|
|
self._custom_templates[name] = str(template_path)
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
def delete_custom_template(self, name: str) -> bool:
|
|
"""Delete a custom template."""
|
|
if name not in self._custom_templates:
|
|
return False
|
|
|
|
template_path = Path(self._custom_templates[name])
|
|
try:
|
|
if template_path.exists():
|
|
template_path.unlink()
|
|
del self._custom_templates[name]
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
def template_exists(self, template_name: str) -> bool:
|
|
"""Check if a template exists."""
|
|
self._load_custom_templates()
|
|
|
|
if template_name in self._custom_templates:
|
|
return True
|
|
|
|
for cat in ["languages", "ides"]:
|
|
template_path = config.template_dir / cat / f"{template_name}.gitignore"
|
|
if template_path.exists():
|
|
return True
|
|
|
|
return False
|
|
|
|
def search_templates(self, query: str) -> List[str]:
|
|
"""Search for templates matching query."""
|
|
query = query.lower()
|
|
results = []
|
|
|
|
for template_name in self.get_available_templates():
|
|
if query in template_name.lower():
|
|
results.append(template_name)
|
|
|
|
return results
|
|
|
|
def merge_templates(self, template_names: List[str]) -> str:
|
|
"""Merge multiple templates into one."""
|
|
lines_seen: Set[str] = set()
|
|
merged_lines = []
|
|
|
|
for template_name in template_names:
|
|
content = self.get_template_content(template_name)
|
|
if content:
|
|
for line in content.splitlines():
|
|
line = line.strip()
|
|
if line and not line.startswith("#"):
|
|
normalized = line.rstrip("/")
|
|
if normalized not in lines_seen:
|
|
lines_seen.add(normalized)
|
|
merged_lines.append(line)
|
|
|
|
return "\n".join(sorted(set(merged_lines)))
|
|
|
|
|
|
template_loader = TemplateLoader()
|