mirror of
https://github.com/crosspoint-reader/crosspoint-reader.git
synced 2026-08-13 14:21:57 -07:00
107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
"""
|
|
PlatformIO pre-build script: inject git branch and short SHA into
|
|
CROSSPOINT_VERSION for the default (dev) environment.
|
|
|
|
Results in a version string like: 1.1.0-dev-feat-kosync-xpath-05c6cf8
|
|
Release environments are unaffected; they set CROSSPOINT_VERSION in the ini.
|
|
"""
|
|
|
|
import configparser
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def warn(msg):
|
|
print(f'WARNING [git_branch.py]: {msg}', file=sys.stderr)
|
|
|
|
|
|
def run_git_value(project_dir, args, label):
|
|
try:
|
|
value = subprocess.check_output(
|
|
['git', *args],
|
|
text=True, stderr=subprocess.PIPE, cwd=project_dir
|
|
).strip()
|
|
# Strip characters that would break a C string literal
|
|
return ''.join(c for c in value if c not in '"\\')
|
|
except FileNotFoundError:
|
|
warn(f'git not found on PATH; {label} suffix will be "unknown"')
|
|
return 'unknown'
|
|
except subprocess.CalledProcessError as e:
|
|
warn(
|
|
f'git command failed (exit {e.returncode}): '
|
|
f'{e.stderr.strip()}; {label} suffix will be "unknown"'
|
|
)
|
|
return 'unknown'
|
|
except OSError as e:
|
|
warn(
|
|
f'OS error reading git {label}: {e}; '
|
|
f'{label} suffix will be "unknown"'
|
|
)
|
|
return 'unknown'
|
|
except Exception as e: # pylint: disable=broad-exception-caught
|
|
warn(
|
|
f'Unexpected error reading git {label}: {e}; '
|
|
f'{label} suffix will be "unknown"'
|
|
)
|
|
return 'unknown'
|
|
|
|
|
|
def get_git_branch(project_dir):
|
|
branch = run_git_value(
|
|
project_dir, ['rev-parse', '--abbrev-ref', 'HEAD'], 'branch'
|
|
)
|
|
# Detached HEAD has no branch name.
|
|
if branch == 'HEAD':
|
|
return 'detached'
|
|
return branch
|
|
|
|
|
|
def get_git_short_sha(project_dir):
|
|
return run_git_value(
|
|
project_dir, ['rev-parse', '--short', 'HEAD'], 'short SHA'
|
|
)
|
|
|
|
|
|
def get_base_version(project_dir):
|
|
ini_path = os.path.join(project_dir, 'platformio.ini')
|
|
if not os.path.isfile(ini_path):
|
|
warn(f'platformio.ini not found at {ini_path}; base version will be "0.0.0"')
|
|
return '0.0.0'
|
|
config = configparser.ConfigParser()
|
|
config.read(ini_path, encoding='utf-8')
|
|
if not config.has_option('crosspoint', 'version'):
|
|
warn('No [crosspoint] version in platformio.ini; base version will be "0.0.0"')
|
|
return '0.0.0'
|
|
return config.get('crosspoint', 'version')
|
|
|
|
|
|
def inject_version(env):
|
|
# Only applies to the dev (default) environment; release envs set the
|
|
# version via build_flags in platformio.ini and are unaffected.
|
|
if env['PIOENV'] != 'default':
|
|
return
|
|
|
|
project_dir = env['PROJECT_DIR']
|
|
base_version = get_base_version(project_dir)
|
|
branch = get_git_branch(project_dir)
|
|
short_sha = get_git_short_sha(project_dir)
|
|
version_string = f'{base_version}-dev-{branch}-{short_sha}'
|
|
|
|
env.Append(CPPDEFINES=[('CROSSPOINT_VERSION', f'\\"{version_string}\\"')])
|
|
print(f'CrossPoint build version: {version_string}')
|
|
|
|
|
|
# PlatformIO/SCons entry point — Import and env are SCons builtins injected at runtime.
|
|
# When run directly with Python (e.g. for validation), a lightweight fake env is used
|
|
# so the git/version logic can be exercised without a full build.
|
|
try:
|
|
Import('env') # noqa: F821 # type: ignore[name-defined]
|
|
inject_version(env) # noqa: F821 # type: ignore[name-defined]
|
|
except NameError:
|
|
class _Env(dict):
|
|
def Append(self, **_): pass
|
|
|
|
_project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
inject_version(_Env({'PIOENV': 'default', 'PROJECT_DIR': _project_dir}))
|