Skip to content

Commit

Permalink
Simplify package versioning (remove EXTRA)
Browse files Browse the repository at this point in the history
  • Loading branch information
mario4tier committed Nov 22, 2024
1 parent 23b7b6d commit 3535b5e
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 54 deletions.
10 changes: 3 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.22)

PROJECT(ta-lib)

SET(TA_LIB_VERSION_MAJOR 0)
SET(TA_LIB_VERSION_MINOR 6)
SET(TA_LIB_VERSION_BUILD 0)
SET(TA_LIB_VERSION_EXTRA "dev")
set(TA_LIB_VERSION_MAJOR 0)
set(TA_LIB_VERSION_MINOR 6)
set(TA_LIB_VERSION_BUILD 0)

SET(TA_LIB_VERSION_FULL "${TA_LIB_VERSION_MAJOR}.${TA_LIB_VERSION_MINOR}.${TA_LIB_VERSION_BUILD}")
IF(TA_LIB_VERSION_EXTRA)
SET(TA_LIB_VERSION_FULL "${TA_LIB_VERSION_FULL}-${TA_LIB_VERSION_EXTRA}")
ENDIF(TA_LIB_VERSION_EXTRA)

INCLUDE(CheckIncludeFiles)
INCLUDE(CheckFunctionExists)
Expand Down
5 changes: 3 additions & 2 deletions scripts/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
import zipfile
import zlib

from utilities.common import verify_git_repo, get_version_string, verify_src_package
from utilities.versions import sync_versions
from utilities.common import verify_git_repo, verify_src_package
from utilities.files import compare_tar_gz_files, compare_zip_files, create_zip_file

def package_windows(root_dir: str, version: str):
Expand Down Expand Up @@ -195,7 +196,7 @@ def package_linux(root_dir: str, version: str):

if __name__ == "__main__":
root_dir = verify_git_repo()
version = get_version_string(root_dir)
version = sync_versions(root_dir)
host_platform = sys.platform
if host_platform == "linux":
package_linux(root_dir,version)
Expand Down
13 changes: 11 additions & 2 deletions scripts/test-dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import platform
import tempfile

from utilities.common import verify_git_repo, get_version_string, create_temp_dir
from utilities.versions import get_version_string, get_version_string_cmake
from utilities.common import verify_git_repo,create_temp_dir
from install_tests.python import test_python_windows, test_python_linux

if __name__ == "__main__":
Expand All @@ -28,9 +29,17 @@
sudo_pwd = args.pwd

root_dir = verify_git_repo()
version = get_version_string(root_dir)

temp_dir = create_temp_dir(root_dir)

# Verify that CMakelists.txt and ta_version.c are in sync.
version = get_version_string(root_dir)
version_cmake = get_version_string_cmake(root_dir)
if version != version_cmake:
print(f"Version mismatch: ta_version.c [{version}] vs CMakeLists.txt [{version_cmake}]")
print(f"Run 'script/package.py' to sync the version numbers in both files.")
sys.exit(1)

# Identify the dist package to test by this host.
host_platform = sys.platform
if host_platform == "linux":
Expand Down
36 changes: 0 additions & 36 deletions scripts/utilities/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,39 +100,3 @@ def verify_src_package(root_dir: str) -> bool:

return True


def get_version_string(root_dir: str) -> str:
"""
Parse the file src/ta_common/ta_version.c to build a version string.
The file contains the following C definitions:
#define MAJOR "0"
#define MINOR "6"
#define BUILD "0"
#define EXTRA "dev"
These become the string "0.6.0-dev".
"""
version_info = {}
version_file_path = os.path.join(root_dir, 'src/ta_common/ta_version.c')
with open(version_file_path) as f:
lines = f.readlines()
for line in lines:
if line.startswith('#define'):
parts = line.split()
if len(parts) == 3:
key = parts[1]
value = parts[2].strip('"')
version_info[key] = value

# Check if MAJOR, MINOR, and BUILD are defined
if 'MAJOR' not in version_info or 'MINOR' not in version_info or 'BUILD' not in version_info:
print("Error: MAJOR, MINOR, and BUILD must be defined in src/ta_common/ta_version.h")
sys.exit(1)

version_string = f"{version_info.get('MAJOR', '0')}.{version_info.get('MINOR', '0')}.{version_info.get('BUILD', '0')}"
if 'EXTRA' in version_info and version_info['EXTRA']:
version_string += f"-{version_info['EXTRA']}"

return version_string

238 changes: 238 additions & 0 deletions scripts/utilities/versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import os
import re
import sys

def _read_version_info(version_file_path: str, version_pattern: str) -> dict:
"""
Read a version string from a file.
version_pattern must be a regular expression with a first group
that includes MAJOR, MINOR, BUILD tokens. In other words, the
keys must be present on the line being selected by the pattern.
The second regex group must be the value of the token.
Returns a dictionary with the keys 'MAJOR', 'MINOR', 'BUILD'.
"""
version_info = {'MAJOR': None, 'MINOR': None, 'BUILD': None}

with open(version_file_path, 'r') as file:
for line in file:
match = version_pattern.search(line)
if match:
key = match.group(1)
value = match.group(2).strip('"')
version_info[key] = value

if None in version_info.values():
print(f"Error: MAJOR, MINOR, and BUILD must be defined in {version_file_path}")
sys.exit(1)

return version_info

def _version_info_to_string(version_info: dict) -> str:
"""
Convert a version information dictionary to a version string.
The dictionary must have the keys 'MAJOR', 'MINOR', 'BUILD'.
"""
# Verify that all keys are defined.
if None in version_info.values():
print(f"Error: MAJOR, MINOR, and BUILD must be defined in {version_info}")
sys.exit(1)

return f"{version_info.get('MAJOR', '0')}.{version_info.get('MINOR', '0')}.{version_info.get('BUILD', '0')}"

def _split_version_string(version: str) -> dict:
"""
Split a version string into its components.
The version string must be in the format "0.0.0"
Returns a dictionary with the keys 'MAJOR', 'MINOR', 'BUILD'
"""
version_info = {'MAJOR': None, 'MINOR': None, 'BUILD': None}

dot_parts = version.split('.')
if len(dot_parts) != 3:
print(f"Error: version must be in format '0.0.0' got instead [{version}]")
sys.exit(1)

version_info['MAJOR'], version_info['MINOR'], version_info['BUILD'] = dot_parts

return version_info

def get_version_string(root_dir: str) -> str:
"""
Parse the file src/ta_common/ta_version.c to build a version string.
The file contains the following C definitions:
#define MAJOR "0"
#define MINOR "6"
#define BUILD "0"
These become the string "0.6.0".
"""

version_file_path = os.path.join(root_dir, "src", "ta_common", "ta_version.c")
version_pattern = re.compile(r'#define\s+(MAJOR|MINOR|BUILD)\s+"(.*?)"')

version_info = _read_version_info(version_file_path, version_pattern)

return _version_info_to_string(version_info)

def get_version_string_cmake(root_dir: str) -> str:
"""
Similar to get_version_string() but parse CMakeLists.txt instead of ta_version.c
Excerpt of the file:
SET(TA_LIB_VERSION_MAJOR 0)
SET(TA_LIB_VERSION_MINOR 6)
SET(TA_LIB_VERSION_BUILD 0)
"""
version_file_path = os.path.join(root_dir, "CMakeLists.txt")
version_pattern = re.compile(r'set\s*\(\s*TA_LIB_VERSION_(MAJOR|MINOR|BUILD)\s+(\d+)\s*\)', re.IGNORECASE)

version_info = _read_version_info(version_file_path, version_pattern)

return _version_info_to_string(version_info)


def set_version_string(root_dir: str, new_version:str):
"""
Counterpart to get_version_string() that updates the src/ta_common/ta_version.c
"""
version_file_path = os.path.join(root_dir, "src", "ta_common", "ta_version.c")

current_version = get_version_string(root_dir)

if current_version == new_version:
return # No changes needed. The version is already up to date.

version_info = _split_version_string(new_version)

# Read the ta_version.c file
with open(version_file_path, 'r') as version_file:
lines = version_file.readlines()

# Update the version information in the lines
version_pattern = re.compile(r'#define\s+(MAJOR|MINOR|BUILD)\s+"(.*?)"')
found_keys = set()
for i, line in enumerate(lines):
match = version_pattern.search(line)
if match:
key = match.group(1)
if key in version_info:
value = version_info[key]
lines[i] = f'#define {key} "{value}"\n'
found_keys.add(key)

# Check if all required keys were found
if not all(k in found_keys for k in ['MAJOR', 'MINOR', 'BUILD']):
print(f"Error: MAJOR, MINOR, and BUILD must be defined in {version_file_path}")
sys.exit(1)

# Write the updated lines back to the ta_version.c file
with open(version_file_path, 'w') as version_file:
version_file.writelines(lines)

def set_version_string_cmake(root_dir: str, new_version:str):
"""
Counterpart to get_version_string_cmake() that updates the
file with the provided new_version string.
The SET(TA_LIB_VERSION_XXXXXX, VALUE) pattern must already be present in the file,
so only the VALUE portion need to be modified.
If a given TA_LIB_VERSION_XXXXXX is not found in the file, the function will
fail with a sys.exit(1).
Excerpt of the file:
SET(TA_LIB_VERSION_MAJOR 0)
SET(TA_LIB_VERSION_MINOR 6)
SET(TA_LIB_VERSION_BUILD 0)
Example of new_version: "0.12.2"
"""

version_file_path = os.path.join(root_dir, "CMakeLists.txt")

current_version = get_version_string_cmake(root_dir)

if current_version == new_version:
return # No changes needed. The version is already up to date.

version_info = _split_version_string(new_version)

# Read the CMakeLists.txt file
with open(version_file_path, 'r') as cmake_file:
lines = cmake_file.readlines()

# Update the version information in the lines
version_pattern = re.compile(r'set\s*\(\s*TA_LIB_VERSION_(MAJOR|MINOR|BUILD)\s+.*\)', re.IGNORECASE)
found_keys = set()
for i, line in enumerate(lines):
match = version_pattern.search(line)
if match:
key = match.group(1)
if key in version_info:
value = version_info[key]
lines[i] = f'set(TA_LIB_VERSION_{key} {value})\n'
found_keys.add(key)

# Check if all required keys were found
if not all(k in found_keys for k in ['MAJOR', 'MINOR', 'BUILD']):
print(f"Error: MAJOR, MINOR, and BUILD must be defined in {version_file_path}")
sys.exit(1)

# Write the updated lines back to the CMakeLists.txt file
with open(version_file_path, 'w') as cmake_file:
cmake_file.writelines(lines)


def compare_version(version1: str, version2: str) -> int:
"""
Compare two version strings.
The format is 0.0.0
Returns:
-1 if version1 < version2
0 if version1 == version2
1 if version1 > version2
"""

# Compare the parts as integer values
v1_parts = list(map(int, version1.split('.')))
v2_parts = list(map(int, version2.split('.')))
for v1_part, v2_part in zip(v1_parts, v2_parts):
if v1_part > v2_part:
return 1
elif v1_part < v2_part:
return -1

return 0 # Identical versions


def sync_versions(root_dir: str) -> str:
"""
Synchronize the version between ta_version.c and CMakeLists.txt.
The versions are first read from both. The highest version is selected.
If the versions are the same, the function will touch nothing.
If one file has a lower version, it is updated with the highest version.
"""
version_c = get_version_string(root_dir)
version_cmake = get_version_string_cmake(root_dir)

compare_result: int = compare_version(version_c, version_cmake)
if compare_result > 0:
print(f"Updating CMakeLists.txt to ta_version.c [{version_c}]")
set_version_string_cmake(root_dir, version_c)
elif compare_result < 0:
print(f"Updating ta_version.c to CMakeLists.txt [{version_cmake}]")
set_version_string(root_dir, version_cmake)

return version_c
10 changes: 3 additions & 7 deletions src/ta_common/ta_version.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,14 @@
#define MAJOR "0"
#define MINOR "6"
#define BUILD "0"
#define EXTRA ""

/* Nothing to modify below this line. */

#define TA_VERSION_DT "(" __DATE__ " " __TIME__ ")"

const char *TA_GetVersionString( void )
{
if (sizeof(EXTRA) > 1) {
return MAJOR "." MINOR "." BUILD "-" EXTRA " " TA_VERSION_DT;
} else {
return MAJOR "." MINOR "." BUILD " " TA_VERSION_DT;
}
return MAJOR "." MINOR "." BUILD " " TA_VERSION_DT;
}

const char *TA_GetVersionMajor( void )
Expand All @@ -73,7 +68,8 @@ const char *TA_GetVersionBuild( void )

const char *TA_GetVersionExtra( void )
{
return EXTRA;
/* Deprecated */
return "";
}

const char *TA_GetVersionDate( void )
Expand Down

0 comments on commit 3535b5e

Please sign in to comment.