# Added generating of new version for each DX Compiler build. # There are 3 kinds of version: # 1. **Official build** # Built by using `hctbuild -official`. The version is based on the current DXIL version, latest official # release and a number of commits since then. The format is `dxil_major.dxil_minor.release_no.commit_count`. # For example a current official version would be something like `1.5.1905.42`. The latest release # information is read from `utils\version\latest-release.json`. The `1905` corresponds to `dxil-2019-05-16` # release branch and `42` is the number of commits since that release branch was created. For master branch # the `commit_count` will be incremented by 10000 to distinguish it from stabilized official release branch # builds. So the current official version of master would be someting like `1.5.1905.10042`. # 2. **Dev build** # Build by using `hctbuild` with no other version-related option. # The format is `dxil_major.dxil_minor.0.commit_count` where commit_count is the number of total commits # since the beginning of the project. # 3. **Fixed version build** # Build by using `hctbuild -fv`. Enables overriding of the version information. The fixed version is # read from `utils\version\version.inc`. Location of the version file can be overriden by `-fvloc` option # on `hctbuild`. # In addition to the numbered version the product version string on the binaries will also include branch # name and last commit sha - `"1.5.1905.10042 (master, 47e31c8a)"`. This product version string is included # in `dxc -?` output. import argparse import json import os import re import subprocess def get_output_of(cmd): enlistment_root=os.path.dirname(os.path.abspath( __file__ )) output = subprocess.check_output(cmd, cwd=enlistment_root) return output.decode('ASCII').strip() def get_last_commit_sha(): try: return get_output_of([ "git", "describe", "--always", "--dirty" ]) except subprocess.CalledProcessError: return "00000000" def get_current_branch(): try: return get_output_of([ "git", "rev-parse", "--abbrev-ref", "HEAD" ]) except subprocess.CalledProcessError: return "private" def get_commit_count(sha): try: return get_output_of([ "git", "rev-list", "--count", sha ]) except subprocess.CalledProcessError: return 0 def read_latest_release_info(): latest_release_file = os.path.join(os.path.dirname(os.path.abspath( __file__)), "latest-release.json") with open(latest_release_file, 'r') as f: return json.load(f) class VersionGen(): def __init__(self, options): self.options = options self.latest_release_info = read_latest_release_info() self.current_branch = get_current_branch() self.rc_version_field_4_cache = None def rc_version_field_1(self): return self.latest_release_info["version"]["major"] def rc_version_field_2(self): return self.latest_release_info["version"]["minor"] def rc_version_field_3(self): return self.latest_release_info["version"]["rev"] if self.options.official else "0" def rc_version_field_4(self): if self.rc_version_field_4_cache is None: base_commit_count = 0 if self.options.official: base_commit_count = int(get_commit_count(self.latest_release_info["sha"])) current_commit_count = int(get_commit_count("HEAD")) distance_from_base = current_commit_count - base_commit_count if (self.current_branch == "master"): distance_from_base += 10000 self.rc_version_field_4_cache = str(distance_from_base) return self.rc_version_field_4_cache def quoted_version_str(self): return '"{}.{}.{}.{}"'.format( self.rc_version_field_1(), self.rc_version_field_2(), self.rc_version_field_3(), self.rc_version_field_4()) def product_version_str(self): if (self.options.no_commit_sha): return self.quoted_version_str() else: return '"{}.{}.{}.{} ({}, {})"'.format( self.rc_version_field_1(), self.rc_version_field_2(), self.rc_version_field_3(), self.rc_version_field_4(), self.current_branch, get_last_commit_sha() ) def print_define(self, name, value): print('#ifdef {}'.format(name)) print('#undef {}'.format(name)) print('#endif') print('#define {} {}'.format(name, value)) print() def print_version(self): print('#pragma once') print() self.print_define('RC_COMPANY_NAME', '"Microsoft(r) Corporation"') self.print_define('RC_VERSION_FIELD_1', self.rc_version_field_1()) self.print_define('RC_VERSION_FIELD_2', self.rc_version_field_2()) self.print_define('RC_VERSION_FIELD_3', self.rc_version_field_3() if self.options.official else "0") self.print_define('RC_VERSION_FIELD_4', self.rc_version_field_4()) self.print_define('RC_FILE_VERSION', self.quoted_version_str()) self.print_define('RC_FILE_DESCRIPTION', '"DirectX Compiler - Out Of Band"') self.print_define('RC_COPYRIGHT', '"(c) Microsoft Corporation. All rights reserved."') self.print_define('RC_PRODUCT_NAME', '"Microsoft(r) DirectX for Windows(r) - Out Of Band"') self.print_define('RC_PRODUCT_VERSION', self.product_version_str()) def main(): p = argparse.ArgumentParser("gen_version") p.add_argument("--no-commit-sha", action='store_true') p.add_argument("--official", action="store_true") args = p.parse_args() VersionGen(args).print_version() if __name__ == '__main__': main()