""" Version information for MarkiTect. This module provides version and release information for the MarkiTect package. Version information is sourced from pyproject.toml and git metadata when available. """ import os import subprocess from pathlib import Path from typing import Optional # Base version from pyproject.toml __version__ = "0.1.0" def get_git_commit_hash() -> Optional[str]: """Get the current git commit hash if available.""" try: result = subprocess.run( ['git', 'rev-parse', '--short', 'HEAD'], capture_output=True, text=True, check=True, cwd=Path(__file__).parent.parent ) return result.stdout.strip() except (subprocess.CalledProcessError, FileNotFoundError): return None def get_git_branch() -> Optional[str]: """Get the current git branch if available.""" try: result = subprocess.run( ['git', 'branch', '--show-current'], capture_output=True, text=True, check=True, cwd=Path(__file__).parent.parent ) return result.stdout.strip() except (subprocess.CalledProcessError, FileNotFoundError): return None def get_git_tag() -> Optional[str]: """Get the current git tag if available.""" try: result = subprocess.run( ['git', 'describe', '--tags', '--exact-match'], capture_output=True, text=True, check=True, cwd=Path(__file__).parent.parent ) return result.stdout.strip() except (subprocess.CalledProcessError, FileNotFoundError): return None def is_development_version() -> bool: """Check if this is a development version (has uncommitted changes).""" try: result = subprocess.run( ['git', 'status', '--porcelain'], capture_output=True, text=True, check=True, cwd=Path(__file__).parent.parent ) return bool(result.stdout.strip()) except (subprocess.CalledProcessError, FileNotFoundError): return False def get_version_info() -> dict: """Get comprehensive version information.""" git_commit = get_git_commit_hash() git_branch = get_git_branch() git_tag = get_git_tag() is_dev = is_development_version() # Build version string version_parts = [__version__] if git_tag and git_tag != f"v{__version__}": # If we have a different tag, use it version_parts = [git_tag.lstrip('v')] if git_commit: if is_dev: version_parts.append(f"dev+{git_commit}") elif not git_tag: version_parts.append(f"+{git_commit}") if is_dev and not git_commit: version_parts.append("dev") full_version = ".".join(version_parts) return { "version": __version__, "full_version": full_version, "git_commit": git_commit, "git_branch": git_branch, "git_tag": git_tag, "is_development": is_dev, "is_git_repo": git_commit is not None } def get_release_info() -> dict: """Get release information.""" version_info = get_version_info() release_type = "development" if version_info["is_development"] else "release" if version_info["git_tag"]: release_type = "tagged-release" elif version_info["git_commit"] and not version_info["is_development"]: release_type = "commit-build" return { "release_type": release_type, "build_from": version_info["git_branch"] or "unknown", "commit": version_info["git_commit"] or "unknown", "clean_build": not version_info["is_development"], **version_info }