| #!/usr/bin/env python3 |
| # Copyright (C) 2020 The Android Open Source Project |
| # |
| # Licensed 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. |
| """ |
| Writes the perfetto_version{.gen.h, .ts} files. |
| |
| This tool is run as part of a genrule from GN, SoonG and Bazel builds. It |
| generates a source header (or in the case of --ts_out a TypeScript file) that |
| contains: |
| - The version number (e.g. v9.0) obtained parsing the CHANGELOG file. |
| - The git HEAD's commit-ish (e.g. 6b330b772b0e973f79c70ba2e9bb2b0110c6715d) |
| |
| The latter is concatenated to the version number to disambiguate builds made |
| from release tags vs builds made from the main branch vs UI builds made from the |
| ui-canary/ui-stable branch. |
| """ |
| |
| import argparse |
| import os |
| import re |
| import sys |
| import subprocess |
| |
| # Note: PROJECT_ROOT is not accurate in bazel builds, where this script is |
| # executed in the bazel sandbox. |
| PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) |
| SCM_REV_NOT_AVAILABLE = 'N/A' |
| |
| |
| def get_latest_release(changelog_path): |
| """Returns a string like 'v9.0'. |
| |
| It does so by searching the latest version mentioned in the CHANGELOG.""" |
| if not changelog_path: |
| if os.path.exists('CHANGELOG'): |
| changelog_path = 'CHANGELOG' |
| else: |
| changelog_path = os.path.join(PROJECT_ROOT, 'CHANGELOG') |
| with open(changelog_path) as f: |
| for line in f.readlines(): |
| m = re.match('^(v\d+[.]\d+)\s.*$', line) |
| if m is not None: |
| return m.group(1) |
| raise Exception('Failed to fetch Perfetto version from %s' % changelog_path) |
| |
| |
| def get_git_sha1(commitish): |
| """Returns the SHA1 of the provided commit-ish""" |
| commit_sha1 = SCM_REV_NOT_AVAILABLE |
| git_dir = os.path.join(PROJECT_ROOT, '.git') |
| if os.path.exists(git_dir): |
| try: |
| commit_sha1 = subprocess.check_output(['git', 'rev-parse', commitish], |
| cwd=PROJECT_ROOT).strip().decode() |
| except subprocess.CalledProcessError: |
| pass |
| return commit_sha1 |
| |
| |
| def write_if_unchanged(path, content): |
| prev_content = None |
| if os.path.exists(path): |
| with open(path, 'r') as fprev: |
| prev_content = fprev.read() |
| if prev_content == content: |
| return 0 |
| with open(path, 'w') as fout: |
| fout.write(content) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--check_git', action='store_true') |
| parser.add_argument( |
| '--no_git', |
| action='store_true', |
| help='Skips running git rev-parse, emits only the version from CHANGELOG') |
| parser.add_argument('--cpp_out', help='Path of the generated .h file.') |
| parser.add_argument('--ts_out', help='Path of the generated .ts file.') |
| parser.add_argument('--stdout', help='Write to stdout', action='store_true') |
| parser.add_argument('--changelog', help='Path to CHANGELOG.') |
| args = parser.parse_args() |
| |
| if args.check_git: |
| has_git = os.path.exists(os.path.join(PROJECT_ROOT, '.git', 'HEAD')) |
| print('1' if has_git else '0') |
| return 0 |
| |
| release = get_latest_release(args.changelog) |
| |
| if args.no_git: |
| head_sha1 = SCM_REV_NOT_AVAILABLE |
| else: |
| head_sha1 = get_git_sha1('HEAD') # SCM_REV_NOT_AVAILABLE on failure. |
| |
| if head_sha1 == SCM_REV_NOT_AVAILABLE: |
| version = release # e.g., 'v9.0'. |
| else: |
| sha1_abbrev = head_sha1[:9] |
| version = f'{release}-{sha1_abbrev}' # e.g., 'v9.0-adeadbeef'. |
| |
| if args.cpp_out: |
| guard = '%s_' % args.cpp_out.upper() |
| guard = re.sub(r'[^\w]', '_', guard) |
| lines = [] |
| lines.append('// Generated by %s' % os.path.basename(__file__)) |
| lines.append('') |
| lines.append('#ifndef %s' % guard) |
| lines.append('#define %s' % guard) |
| lines.append('') |
| lines.append('#define PERFETTO_VERSION_STRING() "%s"' % version) |
| lines.append('#define PERFETTO_VERSION_SCM_REVISION() "%s"' % head_sha1) |
| lines.append('') |
| lines.append('#endif // %s' % guard) |
| lines.append('') |
| content = '\n'.join(lines) |
| write_if_unchanged(args.cpp_out, content) |
| |
| if args.ts_out: |
| lines = [] |
| lines.append('export const VERSION = "%s";' % version) |
| lines.append('export const SCM_REVISION = "%s";' % head_sha1) |
| content = '\n'.join(lines) |
| write_if_unchanged(args.ts_out, content) |
| |
| if args.stdout: |
| print(version) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |