Files
2025-10-13 17:37:32 +02:00

203 lines
7.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Version synchronization script for Text Texture Generator.
Updates version information from git tags across all template files.
"""
import os
import sys
import json
import re
import subprocess
from pathlib import Path
from typing import Dict, Tuple, Optional
def get_project_root() -> Path:
"""Get the project root directory."""
return Path(__file__).parent.parent
def load_config() -> Dict:
"""Load build configuration."""
config_path = get_project_root() / "build" / "config.json"
with open(config_path, 'r') as f:
return json.load(f)
def get_latest_git_tag() -> Optional[str]:
"""Get the latest git tag that matches the version pattern."""
try:
# Get all tags sorted by version
result = subprocess.run(['git', 'tag', '-l', '--sort=-version:refname'],
capture_output=True, text=True, check=True)
tags = result.stdout.strip().split('\n')
config = load_config()
pattern = config['versions']['git_tag_pattern']
version_regex = re.compile(pattern)
for tag in tags:
if version_regex.match(tag):
# Extract version number, removing 'v' prefix if present
match = version_regex.match(tag)
return match.group(1) if match else None
return None
except subprocess.CalledProcessError:
print("Warning: Could not get git tags. Using fallback version.")
return None
def get_version_info(version_string: str) -> Tuple[str, int, int, int]:
"""Parse version string into components."""
parts = version_string.split('.')
if len(parts) != 3:
raise ValueError(f"Invalid version format: {version_string}")
major, minor, patch = map(int, parts)
return version_string, major, minor, patch
def create_template_variables(config: Dict, version: str, version_type: str = "full") -> Dict[str, str]:
"""Create template variables for file generation."""
version_str, major, minor, patch = get_version_info(version)
# Load exclusions configuration for version limits
exclusions_path = get_project_root() / "build" / "file_exclusions.json"
with open(exclusions_path, 'r') as f:
exclusions_config = json.load(f)
# Get version-specific configuration
version_config = exclusions_config['version_configs'][version_type]
# Define features based on version type
if version_type == "free":
enabled_features = ["basic", "preview"]
else: # full version
enabled_features = ["basic", "preview", "image_overlays", "basic_utilities", "advanced_styling", "normal_maps", "presets", "batch_processing", "advanced_utilities", "text_fitting"]
# Parse Blender version
blender_version = config['project']['blender_version_min']
blender_parts = blender_version.split('.')
blender_major, blender_minor = int(blender_parts[0]), int(blender_parts[1])
blender_patch = int(blender_parts[2]) if len(blender_parts) > 2 else 0
# Format dependencies for TOML
deps = []
for dep, version_spec in config['dependencies'].items():
deps.append(f'{dep} = "{version_spec}"')
dependencies_str = '\n'.join(deps)
variables = {
'PROJECT_ID': config['project']['id'],
'PROJECT_NAME': config['project']['name'],
'PROJECT_AUTHOR': config['project']['author'],
'PROJECT_DESCRIPTION': config['project']['description'],
'PROJECT_CATEGORY': config['project']['category'],
'PROJECT_LOCATION': config['project']['location'],
'PROJECT_SUPPORT': config['project']['support'],
'PROJECT_TAGS': json.dumps(config['project']['tags']),
'PROJECT_LICENSE': json.dumps(config['project']['license']),
'VERSION': version_str,
'VERSION_MAJOR': str(major),
'VERSION_MINOR': str(minor),
'VERSION_PATCH': str(patch),
'VERSION_TYPE': version_type,
'BLENDER_VERSION_MIN': blender_version,
'BLENDER_VERSION_MAJOR': str(blender_major),
'BLENDER_VERSION_MINOR': str(blender_minor),
'BLENDER_VERSION_PATCH': str(blender_patch),
'DEPENDENCIES': dependencies_str,
'ENABLED_FEATURES': json.dumps(enabled_features),
'MAX_CONCURRENT_OPERATIONS': str(version_config['max_concurrent_operations'])
}
return variables
def process_template(template_path: Path, output_path: Path, variables: Dict[str, str]):
"""Process a template file and write the output."""
print(f"Processing template: {template_path} -> {output_path}")
# Read template
with open(template_path, 'r') as f:
content = f.read()
# Replace variables
for key, value in variables.items():
content = content.replace(f'{{{{{key}}}}}', value)
# Ensure output directory exists
output_path.parent.mkdir(parents=True, exist_ok=True)
# Write output
with open(output_path, 'w') as f:
f.write(content)
print(f"Generated: {output_path}")
def sync_version(version: Optional[str] = None, version_type: str = "full"):
"""Synchronize version across all template files."""
config = load_config()
# Get version from git tag if not provided
if version is None:
version = get_latest_git_tag()
if version is None:
print("Warning: No valid git tag found. Using version from current blender_manifest.toml")
# Fallback to current version
manifest_path = get_project_root() / "src" / "blender_manifest.toml"
if manifest_path.exists():
with open(manifest_path, 'r') as f:
for line in f:
if line.startswith('version = '):
version = line.split('=')[1].strip().strip('"')
break
if version is None:
version = "1.0.0" # Ultimate fallback
print(f"Synchronizing version: {version} (type: {version_type})")
# Create template variables
variables = create_template_variables(config, version, version_type)
# Add edition-specific variables for __init__.py template
if version_type == "free":
variables.update({
"EDITION_SUFFIX": " (Free)",
"VERSION_PATCH_FINAL": variables['VERSION_PATCH'],
})
else: # full version
variables.update({
"EDITION_SUFFIX": " Pro",
"VERSION_PATCH_FINAL": variables['VERSION_PATCH'],
})
# Process each template file
templates_dir = get_project_root() / "build" / "templates"
for template_file in templates_dir.glob("*.template"):
# Determine output path
relative_name = template_file.stem # Remove .template extension
if relative_name == "blender_manifest.toml":
output_path = get_project_root() / "src" / relative_name
elif relative_name == "constants.py":
output_path = get_project_root() / "src" / "utils" / relative_name
else:
# For other templates, maintain directory structure
output_path = get_project_root() / "src" / relative_name
process_template(template_file, output_path, variables)
print(f"Version synchronization complete: {version}")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Synchronize version information")
parser.add_argument("--version", help="Version to set (defaults to latest git tag)")
parser.add_argument("--type", choices=["free", "full"], default="full",
help="Version type (free or full)")
args = parser.parse_args()
try:
sync_version(args.version, args.type)
except Exception as e:
print(f"Error: {e}")
sys.exit(1)