4.4.6. Making Versioning Consistent¶
When you make a new version / revision of your product, you need to update it at many places. e.g. Number that is shown in about section of a GUI Based program, inside your generated documentation, in the output of --version
of the command line application.
Manually updating it at many places is error-prone. Hence, have a strategy in place that you can be consistent everywhere. You only need to update version number at once place and everywhere else it should get automatically updated.
Here is a sample script (Helper Script: doNewVersion.py) that can generate create a version information files for various applications that you may need while building your software project.
If we run above script with:
python my_version_file_generator.py 1 2 7
the following files are generated.
/* (C) 2024 Purnank */
/* Version information for my_Product for C/C++ files */
#ifndef MY_PRODUCT_VER_H
#define MY_PRODUCT_VER_H
#define MY_PRODUCT_VER_MAJOR (1)
#define MY_PRODUCT_VER_MINOR (2)
#define MY_PRODUCT_VER_DEV (7)
#define MY_PRODUCT_VER_STR "1.2.7"
#endif /* MY_PRODUCT_VER_H *
/* (C) 2024 Purnank */
/* Version information for my_Product for NSIS Installer
*
* Include this file as::
*
* !include /path/to/this/file.nsh
*/
!define MY_PRODUCT_VER_FULLSTRING "my_Product_1.2.7"
!define MY_PRODUCT_VER_FILEVERSION "1.2.7.0"
!define MY_PRODUCT_VER_MAJOR "1"
!define MY_PRODUCT_VER_MINOR "2"
!define MY_PRODUCT_VER_DEV "7"
# (C) 2024 Purnank
# Version information for my_Product for Make Files
#
# Include this file as::
#
# include /path/to/this/file
#
MY_PRODUCT_VER_MAJOR=1
MY_PRODUCT_VER_MINOR=2
MY_PRODUCT_VER_DEV=7
# (C) 2024 Purnank
# Version information for my_Product for CMake Files
#
# Include this file as::
#
# INCLUDE(/path/to/this/file)
#
SET(MY_PRODUCT_VER_MAJOR "1")
SET(MY_PRODUCT_VER_MINOR "2")
SET(MY_PRODUCT_VER_DEV "7")
# (C) 2024 Purnank
# Version information for my_Product for Doxygen
#
# Include this file as::
#
# @INCLUDE /path/to/this/file
#
PROJECT_NUMBER = "v1.2.7"
4.4.6.1. Capturing Git Information¶
You can capture information about the build from Git version control system.
Command | Information | Sample output |
---|---|---|
| Shows human-readable information of your product It depends on an annotated tag (Tag created with either a message for with |
|
| Unique SHA1 of the current commit |
|
| Useful in shell scripts. Returns 0 if there are no changes. Returns 1 if there are changes. | Sample script: git diff --quiet; if [[ $? == 0 ]]; then echo No Changes;
else echo There are changes; fi
|
| Get the current branch name |
|
| Get the TAG for this revision | MY_TAG_v1.2.3 |
| Get the TAG for this revision Same as above | MY_TAG_v1.2.3 |
4.4.6.2. Helper Script: doNewVersion.py
¶
Here is the content of the helper script that can generate version information for various types of build steps.
# (C) 2024 Purnank
""" Helper script to generate version information.
"""
import sys
PRODUCT_NAME = "my_Product"
COPYRIGHT = "(C) 2024 Purnank"
def main():
""" Entry point of the file """
if len(sys.argv) == 4:
all_decimals = map(lambda x: x.isdecimal(), sys.argv[1:])
if False in all_decimals:
usage("Not all version numbers are decimal")
else:
(major, minor, dev) = [int(i) for i in sys.argv[1:]]
my_version_file_generator(major, minor, dev)
elif len(sys.argv) > 4:
usage("Extra arguments passed")
else:
usage("Not enough arguments")
def usage(error):
""" Print Usage """
print("\n")
print("Error: %s\n" % error)
print("Usage:\n")
print(" %s <major> <minor> <dev>" % sys.argv[0])
print("\n")
print("Please ensure <major> <minor> and <dev> are all decimal numbers.")
print("\n")
TEMPLATES_H = """/* {copyright} */
/* Version information for {my_product} for C/C++ files */
#ifndef {my_product_u}_VER_H
#define {my_product_u}_VER_H
#define {my_product_u}_VER_MAJOR ({major})
#define {my_product_u}_VER_MINOR ({minor})
#define {my_product_u}_VER_DEV ({dev})
#define {my_product_u}_VER_STR "{major}.{minor}.{dev}"
#endif /* {my_product_u}_VER_H *
"""
TEMPLATES_NSH = """/* {copyright} */
/* Version information for {my_product} for NSIS Installer
*
* Include this file as::
*
* !include /path/to/this/file.nsh
*/
!define {my_product_u}_VER_FULLSTRING "{my_product}_{major}.{minor}.{dev}"
!define {my_product_u}_VER_FILEVERSION "{major}.{minor}.{dev}.0"
!define {my_product_u}_VER_MAJOR "{major}"
!define {my_product_u}_VER_MINOR "{minor}"
!define {my_product_u}_VER_DEV "{dev}"
"""
TEMPLATES_MAKE = """# {copyright}
# Version information for {my_product} for Make Files
#
# Include this file as::
#
# include /path/to/this/file
#
{my_product_u}_VER_MAJOR={major}
{my_product_u}_VER_MINOR={minor}
{my_product_u}_VER_DEV={dev}
"""
TEMPLATES_CMAKE = """# {copyright}
# Version information for {my_product} for CMake Files
#
# Include this file as::
#
# INCLUDE(/path/to/this/file)
#
SET({my_product_u}_VER_MAJOR "{major}")
SET({my_product_u}_VER_MINOR "{minor}")
SET({my_product_u}_VER_DEV "{dev}")
"""
TEMPLATES_DOXYGEN = """# {copyright}
# Version information for {my_product} for Doxygen
#
# Include this file as::
#
# @INCLUDE /path/to/this/file
#
PROJECT_NUMBER = "v{major}.{minor}.{dev}"
"""
EXTENSION_TEMPLATES = {
".h": TEMPLATES_H,
".nsh": TEMPLATES_NSH,
".mk": TEMPLATES_MAKE,
".cmake": TEMPLATES_CMAKE,
".doxy": TEMPLATES_DOXYGEN,
}
def my_version_file_generator(major, minor, dev):
""" Generate version files for given major.minor.dev """
print("Generating version files for %d.%d.%d" % (major, minor, dev))
values = {
"copyright": COPYRIGHT,
"my_product": PRODUCT_NAME,
"my_product_u": PRODUCT_NAME.upper(),
"major": major,
"minor": minor,
"dev": dev,
}
for ext, template in EXTENSION_TEMPLATES.items():
file_name = "%s_Ver%s" % (PRODUCT_NAME, ext)
with open(file_name, "w") as ver:
ver.write(template.format(**values))
print(".. Updated %s" % file_name)
if __name__ == '__main__':
main()