gen_version.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # Added generating of new version for each DX Compiler build.
  2. # There are 3 kinds of version:
  3. # 1. **Official build**
  4. # Built by using `hctbuild -official`. The version is based on the current DXIL version, latest official
  5. # release and a number of commits since then. The format is `dxil_major.dxil_minor.release_no.commit_count`.
  6. # For example a current official version would be something like `1.5.1905.42`. The latest release
  7. # information is read from `utils\version\latest-release.json`. The `1905` corresponds to `dxil-2019-05-16`
  8. # release branch and `42` is the number of commits since that release branch was created. For master branch
  9. # the `commit_count` will be incremented by 10000 to distinguish it from stabilized official release branch
  10. # builds. So the current official version of master would be someting like `1.5.1905.10042`.
  11. # 2. **Dev build**
  12. # Build by using `hctbuild` with no other version-related option.
  13. # The format is `dxil_major.dxil_minor.0.commit_count` where commit_count is the number of total commits
  14. # since the beginning of the project.
  15. # 3. **Fixed version build**
  16. # Build by using `hctbuild -fv`. Enables overriding of the version information. The fixed version is
  17. # read from `utils\version\version.inc`. Location of the version file can be overriden by `-fvloc` option
  18. # on `hctbuild`.
  19. # In addition to the numbered version the product version string on the binaries will also include branch
  20. # name and last commit sha - `"1.5.1905.10042 (master, 47e31c8a)"`. This product version string is included
  21. # in `dxc -?` output.
  22. import argparse
  23. import json
  24. import os
  25. import re
  26. import subprocess
  27. def get_output_of(cmd):
  28. enlistment_root=os.path.dirname(os.path.abspath( __file__ ))
  29. output = subprocess.check_output(cmd, cwd=enlistment_root)
  30. return output.decode('ASCII').strip()
  31. def get_last_commit_sha():
  32. try:
  33. return get_output_of([ "git", "describe", "--always", "--dirty" ])
  34. except subprocess.CalledProcessError:
  35. return "00000000"
  36. def get_current_branch():
  37. try:
  38. return get_output_of([ "git", "rev-parse", "--abbrev-ref", "HEAD" ])
  39. except subprocess.CalledProcessError:
  40. return "private"
  41. def get_commit_count(sha):
  42. try:
  43. return get_output_of([ "git", "rev-list", "--count", sha ])
  44. except subprocess.CalledProcessError:
  45. return 0
  46. def read_latest_release_info():
  47. latest_release_file = os.path.join(os.path.dirname(os.path.abspath( __file__)), "latest-release.json")
  48. with open(latest_release_file, 'r') as f:
  49. return json.load(f)
  50. class VersionGen():
  51. def __init__(self, options):
  52. self.options = options
  53. self.latest_release_info = read_latest_release_info()
  54. self.current_branch = get_current_branch()
  55. self.rc_version_field_4_cache = None
  56. def rc_version_field_1(self):
  57. return self.latest_release_info["version"]["major"]
  58. def rc_version_field_2(self):
  59. return self.latest_release_info["version"]["minor"]
  60. def rc_version_field_3(self):
  61. return self.latest_release_info["version"]["rev"] if self.options.official else "0"
  62. def rc_version_field_4(self):
  63. if self.rc_version_field_4_cache is None:
  64. base_commit_count = 0
  65. if self.options.official:
  66. base_commit_count = int(get_commit_count(self.latest_release_info["sha"]))
  67. current_commit_count = int(get_commit_count("HEAD"))
  68. distance_from_base = current_commit_count - base_commit_count
  69. if (self.current_branch == "master"):
  70. distance_from_base += 10000
  71. self.rc_version_field_4_cache = str(distance_from_base)
  72. return self.rc_version_field_4_cache
  73. def quoted_version_str(self):
  74. return '"{}.{}.{}.{}"'.format(
  75. self.rc_version_field_1(),
  76. self.rc_version_field_2(),
  77. self.rc_version_field_3(),
  78. self.rc_version_field_4())
  79. def product_version_str(self):
  80. if (self.options.no_commit_sha):
  81. return self.quoted_version_str()
  82. pv = '"{}.{}.{}.{} '.format(
  83. self.rc_version_field_1(),
  84. self.rc_version_field_2(),
  85. self.rc_version_field_3(),
  86. self.rc_version_field_4())
  87. if (self.current_branch != "HEAD"):
  88. pv += '({}, {})"'.format(self.current_branch, get_last_commit_sha())
  89. else:
  90. pv += '({})"'.format(get_last_commit_sha())
  91. return pv
  92. def print_define(self, name, value):
  93. print('#ifdef {}'.format(name))
  94. print('#undef {}'.format(name))
  95. print('#endif')
  96. print('#define {} {}'.format(name, value))
  97. print()
  98. def print_version(self):
  99. print('#pragma once')
  100. print()
  101. self.print_define('RC_COMPANY_NAME', '"Microsoft(r) Corporation"')
  102. self.print_define('RC_VERSION_FIELD_1', self.rc_version_field_1())
  103. self.print_define('RC_VERSION_FIELD_2', self.rc_version_field_2())
  104. self.print_define('RC_VERSION_FIELD_3', self.rc_version_field_3() if self.options.official else "0")
  105. self.print_define('RC_VERSION_FIELD_4', self.rc_version_field_4())
  106. self.print_define('RC_FILE_VERSION', self.quoted_version_str())
  107. self.print_define('RC_FILE_DESCRIPTION', '"DirectX Compiler - Out Of Band"')
  108. self.print_define('RC_COPYRIGHT', '"(c) Microsoft Corporation. All rights reserved."')
  109. self.print_define('RC_PRODUCT_NAME', '"Microsoft(r) DirectX for Windows(r) - Out Of Band"')
  110. self.print_define('RC_PRODUCT_VERSION', self.product_version_str())
  111. def main():
  112. p = argparse.ArgumentParser("gen_version")
  113. p.add_argument("--no-commit-sha", action='store_true')
  114. p.add_argument("--official", action="store_true")
  115. args = p.parse_args()
  116. VersionGen(args).print_version()
  117. if __name__ == '__main__':
  118. main()