| # Licensed to the Apache Software Foundation (ASF) under one | 
 | # or more contributor license agreements.  See the NOTICE file | 
 | # distributed with this work for additional information | 
 | # regarding copyright ownership.  The ASF licenses this file | 
 | # to you under the Apache License, Version 2.0 (the | 
 | # "License"); you may not use this file except in compliance | 
 | # with the License.  You may obtain a copy of the License at | 
 | # | 
 | #   http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # Unless required by applicable law or agreed to in writing, | 
 | # software distributed under the License is distributed on an | 
 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 | # KIND, either express or implied.  See the License for the | 
 | # specific language governing permissions and limitations | 
 | # under the License. | 
 |  | 
 | """ | 
 | This is the global script that set the version information of TVM. | 
 | This script runs and update all the locations that related to versions | 
 |  | 
 | List of affected files: | 
 | - tvm-root/python/tvm/_ffi/libinfo.py | 
 | - tvm-root/include/tvm/runtime/c_runtime_api.h | 
 | - tvm-root/conda/recipe/meta.yaml | 
 | - tvm-root/web/package.json | 
 | """ | 
 | import os | 
 | import re | 
 | import argparse | 
 | import logging | 
 | import subprocess | 
 |  | 
 | # Modify the following value during release | 
 | # --------------------------------------------------- | 
 | # Current version: | 
 | # We use the version of the incoming release for code | 
 | # that is under development. | 
 | # | 
 | # It is also fallback version to be used when --git-describe | 
 | # is not invoked, or when the repository does not present the | 
 | # git tags in a format that this script can use. | 
 | # | 
 | # Two tag formats are supported: | 
 | # - vMAJ.MIN.PATCH (e.g. v0.8.0) or | 
 | # - vMAJ.MIN.devN (e.g. v0.8.dev0) | 
 | __version__ = "0.13.dev0" | 
 |  | 
 | # --------------------------------------------------- | 
 |  | 
 | PROJ_ROOT = os.path.dirname(os.path.abspath(os.path.expanduser(__file__))) | 
 |  | 
 |  | 
 | def py_str(cstr): | 
 |     return cstr.decode("utf-8") | 
 |  | 
 |  | 
 | def git_describe_version(): | 
 |     """Get PEP-440 compatible public and local version using git describe. | 
 |  | 
 |     Returns | 
 |     ------- | 
 |     pub_ver: str | 
 |         Public version. | 
 |  | 
 |     local_ver: str | 
 |         Local version (with additional label appended to pub_ver). | 
 |  | 
 |     Notes | 
 |     ----- | 
 |     - We follow PEP 440's convention of public version | 
 |       and local versions. | 
 |     - Only tags conforming to vMAJOR.MINOR.REV (e.g. "v0.7.0") | 
 |       are considered in order to generate the version string. | 
 |       See the use of `--match` in the `git` command below. | 
 |  | 
 |     Here are some examples: | 
 |  | 
 |     - pub_ver = '0.7.0', local_ver = '0.7.0': | 
 |       We are at the 0.7.0 release. | 
 |     - pub_ver =  '0.8.dev94', local_ver = '0.8.dev94+g0d07a329e': | 
 |       We are at the 0.8 development cycle. | 
 |       The current source contains 94 additional commits | 
 |       after the most recent tag(v0.7.0), | 
 |       the git short hash tag of the current commit is 0d07a329e. | 
 |     """ | 
 |     cmd = [ | 
 |         "git", | 
 |         "describe", | 
 |         "--tags", | 
 |         "--match", | 
 |         "v[0-9]*.[0-9]*.[0-9]*", | 
 |         "--match", | 
 |         "v[0-9]*.[0-9]*.dev[0-9]*", | 
 |     ] | 
 |     proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=PROJ_ROOT) | 
 |     (out, _) = proc.communicate() | 
 |  | 
 |     if proc.returncode != 0: | 
 |         msg = py_str(out) | 
 |         if msg.find("not a git repository") != -1: | 
 |             return __version__, __version__ | 
 |         logging.warning("git describe: %s, use %s", msg, __version__) | 
 |         return __version__, __version__ | 
 |     describe = py_str(out).strip() | 
 |     arr_info = describe.split("-") | 
 |  | 
 |     # Remove the v prefix, mainly to be robust | 
 |     # to the case where v is not presented as well. | 
 |     if arr_info[0].startswith("v"): | 
 |         arr_info[0] = arr_info[0][1:] | 
 |  | 
 |     # hit the exact tag | 
 |     if len(arr_info) == 1: | 
 |         return arr_info[0], arr_info[0] | 
 |  | 
 |     if len(arr_info) != 3: | 
 |         logging.warning("Invalid output from git describe %s", describe) | 
 |         return __version__, __version__ | 
 |  | 
 |     dev_pos = arr_info[0].find(".dev") | 
 |  | 
 |     # Development versions: | 
 |     # The code will reach this point in case it can't match a full release version, such as v0.7.0. | 
 |     # | 
 |     # 1. in case the last known label looks like vMAJ.MIN.devN e.g. v0.8.dev0, we use | 
 |     # the current behaviour of just using vMAJ.MIN.devNNNN+gGIT_REV | 
 |     if dev_pos != -1: | 
 |         dev_version = arr_info[0][: arr_info[0].find(".dev")] | 
 |     # 2. in case the last known label looks like vMAJ.MIN.PATCH e.g. v0.8.0 | 
 |     # then we just carry on with a similar version to what git describe provides, which is | 
 |     # vMAJ.MIN.PATCH.devNNNN+gGIT_REV | 
 |     else: | 
 |         dev_version = arr_info[0] | 
 |  | 
 |     pub_ver = "%s.dev%s" % (dev_version, arr_info[1]) | 
 |     local_ver = "%s+%s" % (pub_ver, arr_info[2]) | 
 |     return pub_ver, local_ver | 
 |  | 
 |  | 
 | # Implementations | 
 | def update(file_name, pattern, repl, dry_run=False): | 
 |     update = [] | 
 |     hit_counter = 0 | 
 |     need_update = False | 
 |     with open(file_name) as file: | 
 |         for l in file: | 
 |             result = re.findall(pattern, l) | 
 |             if result: | 
 |                 assert len(result) == 1 | 
 |                 hit_counter += 1 | 
 |                 if result[0] != repl: | 
 |                     l = re.sub(pattern, repl, l) | 
 |                     need_update = True | 
 |                     print("%s: %s -> %s" % (file_name, result[0], repl)) | 
 |                 else: | 
 |                     print("%s: version is already %s" % (file_name, repl)) | 
 |  | 
 |             update.append(l) | 
 |     if hit_counter != 1: | 
 |         raise RuntimeError("Cannot find version in %s" % file_name) | 
 |  | 
 |     if need_update and not dry_run: | 
 |         with open(file_name, "w") as output_file: | 
 |             for l in update: | 
 |                 output_file.write(l) | 
 |  | 
 |  | 
 | def sync_version(pub_ver, local_ver, dry_run): | 
 |     """Synchronize version.""" | 
 |     # python uses the PEP-440: local version | 
 |     update( | 
 |         os.path.join(PROJ_ROOT, "python", "tvm", "_ffi", "libinfo.py"), | 
 |         r"(?<=__version__ = \")[.0-9a-z\+]+", | 
 |         local_ver, | 
 |         dry_run, | 
 |     ) | 
 |     # Use public version for other parts for now | 
 |     # Note that full git hash is already available in libtvm | 
 |     # C++ header | 
 |     update( | 
 |         os.path.join(PROJ_ROOT, "include", "tvm", "runtime", "c_runtime_api.h"), | 
 |         r'(?<=TVM_VERSION ")[.0-9a-z\+]+', | 
 |         pub_ver, | 
 |         dry_run, | 
 |     ) | 
 |     # conda | 
 |     update( | 
 |         os.path.join(PROJ_ROOT, "conda", "recipe", "meta.yaml"), | 
 |         r"(?<=version = ')[.0-9a-z\+]+", | 
 |         pub_ver, | 
 |         dry_run, | 
 |     ) | 
 |     # web | 
 |     # change to pre-release convention by npm | 
 |     dev_pos = pub_ver.find(".dev") | 
 |     npm_ver = pub_ver if dev_pos == -1 else "%s.0-%s" % (pub_ver[:dev_pos], pub_ver[dev_pos + 1 :]) | 
 |     update( | 
 |         os.path.join(PROJ_ROOT, "web", "package.json"), | 
 |         r'(?<="version": ")[.0-9a-z\-\+]+', | 
 |         npm_ver, | 
 |         dry_run, | 
 |     ) | 
 |  | 
 |  | 
 | def main(): | 
 |     logging.basicConfig(level=logging.INFO) | 
 |     parser = argparse.ArgumentParser(description="Detect and synchronize version.") | 
 |     parser.add_argument( | 
 |         "--print-version", | 
 |         action="store_true", | 
 |         help="Print version to the command line. No changes is applied to files.", | 
 |     ) | 
 |     parser.add_argument( | 
 |         "--git-describe", | 
 |         action="store_true", | 
 |         help="Use git describe to generate development version.", | 
 |     ) | 
 |     parser.add_argument("--dry-run", action="store_true") | 
 |  | 
 |     opt = parser.parse_args() | 
 |     pub_ver, local_ver = __version__, __version__ | 
 |     if opt.git_describe: | 
 |         pub_ver, local_ver = git_describe_version() | 
 |     if opt.print_version: | 
 |         print(local_ver) | 
 |     else: | 
 |         sync_version(pub_ver, local_ver, opt.dry_run) | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     main() |