PageRenderTime 26ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/etc/python/armarx/armarx_version.py

https://gitlab.com/mkroehnert/ArmarXCore
Python | 283 lines | 239 code | 18 blank | 26 comment | 13 complexity | 140f182184d54cac89e76e54cbd083c7 MD5 | raw file
  1. #!/usr/bin/env python2
  2. from __future__ import with_statement, print_function, division
  3. import os
  4. import logging
  5. from argparse import ArgumentParser
  6. from collections import namedtuple
  7. import re
  8. import subprocess
  9. logger = logging.getLogger(__name__)
  10. Version = namedtuple('Version', ['major', 'minor', 'patch'])
  11. armarx_pkgs = {"ArmarXCore", "ArmarXGui", "RobotAPI", "MemoryX", "VisionX",
  12. "RobotComponents", "ArmarXSimulation",
  13. "RobotSkillTemplates", "ArmarXDB"}
  14. armarx_version_file = "etc/cmake/ArmarXPackageVersion.cmake"
  15. def get_version(pkg_name):
  16. pkg_dir = get_armarx_pkg_dir(pkg_name)
  17. version = read_armarx_version(pkg_dir)
  18. return format_version(version)
  19. def read_armarx_version(pkg_dir):
  20. """
  21. get the current armarx version for a package
  22. :param pkg_dir: path to the top level package directory
  23. :returns: the armarx version
  24. :rtype: dict with major minor patch version
  25. """
  26. version = {}
  27. path = os.path.join(pkg_dir, armarx_version_file)
  28. with open(path) as f:
  29. lines = f.readlines()
  30. for l in lines:
  31. match = re.search('.*ARMARX_PACKAGE_LIBRARY_VERSION_([A-Z]*) "(\d+)".*', l)
  32. if match:
  33. x, v = match.groups()
  34. if x.lower() not in Version._fields:
  35. logger.error("error while parsing version file {}".format(path))
  36. raise ValueError('unable to parse version file')
  37. version[x.lower()] = int(v)
  38. return Version(**version)
  39. def get_armarx_pkg_dir(pkg_name):
  40. """
  41. finds the package path for an armarx package
  42. :param pkg_name: name of the package
  43. :returns: the path to the package if found
  44. :rtype: str
  45. """
  46. path = os.path.expanduser("~/.cmake/packages/{}/".format(pkg_name))
  47. l = list(os.listdir(path))
  48. if len(l) != 1:
  49. logger.error("unable to find path for package {}. path is not unique".format(pkg_name))
  50. raise ValueError("unable to find cmake package path")
  51. with open(os.path.join(path, l[0])) as f:
  52. lines = f.readlines()
  53. if len(lines) != 1:
  54. logger.error("unable to find path for package {}".format(pkg_name))
  55. raise ValueError("unable to find cmake package path")
  56. else:
  57. for line in open(os.path.join(lines[0][:-1], 'CMakeCache.txt')):
  58. if line.startswith('Project_SOURCE_DIR'):
  59. return line.split('=')[-1][:-1]
  60. def print_armarx_version(pkg_names):
  61. """
  62. convenience function for printing version number
  63. :param pkg_name: list of package names
  64. """
  65. for p in pkg_names:
  66. pkg_dir = get_armarx_pkg_dir(p)
  67. version = read_armarx_version(pkg_dir)
  68. print("{} {} - {}".format(p, format_version(version), pkg_dir))
  69. def write_armarx_version(pkg_dir, new_version):
  70. """
  71. sets the version in ArmarXPackageVersion.cmake
  72. :param pkg_dir: path to the package
  73. :param new_version: the new version
  74. """
  75. version_file = '''# armarx version file
  76. set(ARMARX_PACKAGE_LIBRARY_VERSION_MAJOR "{}")
  77. set(ARMARX_PACKAGE_LIBRARY_VERSION_MINOR "{}")
  78. set(ARMARX_PACKAGE_LIBRARY_VERSION_PATCH "{}")
  79. '''.format(new_version.major, new_version.minor, new_version.patch)
  80. version_file_footer = '''
  81. set(ARMARX_PACKAGE_LIBRARY_VERSION "${ARMARX_PACKAGE_LIBRARY_VERSION_MAJOR}.${ARMARX_PACKAGE_LIBRARY_VERSION_MINOR}.${ARMARX_PACKAGE_LIBRARY_VERSION_PATCH}")
  82. set(ARMARX_PACKAGE_LIBRARY_SOVERSION "0")
  83. '''
  84. path = os.path.join(pkg_dir, armarx_version_file)
  85. with open(path, 'w') as f:
  86. f.write(version_file)
  87. f.write(version_file_footer)
  88. def update_armarx_python(new_version):
  89. """
  90. sets the version for python utils
  91. .. todo:: python utils should extract the version from the cmake version file
  92. :param new_version: the new version to set
  93. """
  94. version_str = format_version(new_version)[1:]
  95. version_file_content = 'armarx_version = "{}"'.format(version_str)
  96. path = os.path.join(get_armarx_pkg_dir('ArmarXCore'), 'etc/python/__version__.py')
  97. with open(path, 'w') as f:
  98. f.write(version_file_content)
  99. def format_version(version):
  100. """
  101. converts the version dict to a string with the format vx.y.z
  102. where x is the major, y the minor and z the patch
  103. :param version: the version to format
  104. :type version: dict
  105. :rtype: str
  106. """
  107. return 'v{}.{}.{}'.format(version.major, version.minor, version.patch)
  108. def commit_version(pkg_name, pkg_dir, new_version):
  109. """
  110. creates a git commit and tag for the new version
  111. :param pkg_name: name of the package
  112. :param pkg_dir: path to the pacakge
  113. :param new_version: the new version to set
  114. """
  115. os.chdir(pkg_dir)
  116. cmd = 'git checkout stable'
  117. subprocess.check_call([cmd], shell=True)
  118. str_version = format_version(new_version)
  119. subprocess.check_call(['pwd'], shell=True)
  120. cmd = 'git commit -m "version bump to {}" -- "{}"'.format(str_version, armarx_version_file)
  121. if pkg_name == "ArmarXCore":
  122. cmd = cmd + ' etc/python/__version__.py'
  123. subprocess.check_call([cmd], shell=True)
  124. cmd = 'git tag -a {} -m "{} {}"'.format(str_version, pkg_name, str_version)
  125. subprocess.check_call([cmd], shell=True)
  126. def parse_version(v_str):
  127. """
  128. :param v_str: the version string to parse
  129. :returns: the parsed version
  130. :rtype: dict
  131. """
  132. if v_str.startswith("v"):
  133. v_str = v_str[1:]
  134. version = map(int, v_str.split('.'))
  135. version = Version(*version)
  136. if version > Version(0, 0, 0):
  137. return version
  138. def push_version(pkg_dir):
  139. """
  140. convenience function for pushing the git repository
  141. :param pkg_dir: path to the package
  142. """
  143. cmd = 'git push --tags -u origin'
  144. subprocess.check_call([cmd], shell=True)
  145. def increase_version(current_version, bump):
  146. """
  147. increase the version
  148. :param current_version: the current version
  149. :type current_version: dict
  150. :param bump: specifies the version increase
  151. :type bump: str
  152. :return: the increased version
  153. :rtype: dict
  154. """
  155. new_version = list(current_version)
  156. found = False
  157. for i, k in enumerate(Version._fields):
  158. if found:
  159. new_version[i] = 0
  160. elif k == bump:
  161. new_version[i] = current_version[i] + 1
  162. found = True
  163. return Version(*new_version)
  164. def bump_version(bump, pkg_names):
  165. """
  166. convenience function to increase the version
  167. """
  168. new_version = {}
  169. for p in pkg_names:
  170. pkg_dir = get_armarx_pkg_dir(p)
  171. current_version = read_armarx_version(pkg_dir)
  172. bumped_version = increase_version(current_version, bump)
  173. logger.info("new version is {}".format(format_version(bumped_version)))
  174. if not new_version:
  175. new_version = bumped_version
  176. elif new_version != bumped_version:
  177. logger.error("unable to bump version for package {}".format(p))
  178. logger.error("new version is {}. expected {}".format(format_version(bumped_version), format_version(new_version)))
  179. return
  180. set_version(new_version, pkg_names)
  181. def set_version(new_version, pkg_names):
  182. """
  183. set the version
  184. """
  185. logger.info("setting version to {}".format(format_version(new_version)))
  186. pkg_dirs = map(get_armarx_pkg_dir, pkg_names)
  187. for p in pkg_dirs:
  188. current_version = read_armarx_version(p)
  189. logger.debug("{}: {} -> {}".format(p, format_version(current_version), format_version(new_version)))
  190. if not new_version > current_version:
  191. logger.error("invalid version increase from {} to {} in {}".format(current_version, new_version, p))
  192. return
  193. for p in pkg_dirs:
  194. write_armarx_version(p, new_version)
  195. update_armarx_python(new_version)
  196. for pkg_name, pkg_path in zip(pkg_names, pkg_dirs):
  197. commit_version(pkg_name, pkg_path, new_version)
  198. logger.info("push to origin: repo forall -c 'git push'")
  199. logger.info("done.")
  200. def main():
  201. parser = ArgumentParser(description="armarx version script")
  202. verbose_group = parser.add_mutually_exclusive_group()
  203. verbose_group.add_argument('-v', '--verbose', action='store_true', help='be verbose')
  204. verbose_group.add_argument('-q', '--quiet', action='store_true', help='be quiet')
  205. group = parser.add_mutually_exclusive_group()
  206. group.add_argument('-b', '--bump-version', choices=['major', 'minor', 'patch'], help='version bump')
  207. group.add_argument('-s', '--set-version', help='set the version')
  208. group.add_argument('-p', '--print-package', nargs='+', help='print the version for a package name')
  209. # parser.add_argument('-p', '--package', help='limit command to packages')
  210. args = parser.parse_args()
  211. if args.verbose:
  212. logging.basicConfig(level=logging.DEBUG)
  213. elif args.quiet:
  214. logging.basicConfig(level=logging.ERROR)
  215. else:
  216. logging.basicConfig()
  217. if args.print_package:
  218. print_armarx_version(args.print_package)
  219. elif args.bump_version:
  220. bump_version(args.bump_version, armarx_pkgs)
  221. elif args.set_version:
  222. new_version = parse_version(args.set_version)
  223. set_version(new_version, armarx_pkgs)
  224. else:
  225. print_armarx_version(armarx_pkgs)
  226. if __name__ == "__main__":
  227. main()