xref: /aosp_15_r20/external/perfetto/tools/write_version_header.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker#
4*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker#
8*6dbdd20aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker#
10*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker"""
16*6dbdd20aSAndroid Build Coastguard WorkerWrites the perfetto_version{.gen.h, .ts} files.
17*6dbdd20aSAndroid Build Coastguard Worker
18*6dbdd20aSAndroid Build Coastguard WorkerThis tool is run as part of a genrule from GN, SoonG and Bazel builds. It
19*6dbdd20aSAndroid Build Coastguard Workergenerates a source header (or in the case of --ts_out a TypeScript file) that
20*6dbdd20aSAndroid Build Coastguard Workercontains:
21*6dbdd20aSAndroid Build Coastguard Worker- The version number (e.g. v9.0) obtained parsing the CHANGELOG file.
22*6dbdd20aSAndroid Build Coastguard Worker- The git HEAD's commit-ish (e.g. 6b330b772b0e973f79c70ba2e9bb2b0110c6715d)
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard WorkerThe latter is concatenated to the version number to disambiguate builds made
25*6dbdd20aSAndroid Build Coastguard Workerfrom release tags vs builds made from the main branch vs UI builds made from the
26*6dbdd20aSAndroid Build Coastguard Workerui-canary/ui-stable branch.
27*6dbdd20aSAndroid Build Coastguard Worker"""
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard Workerimport argparse
30*6dbdd20aSAndroid Build Coastguard Workerimport os
31*6dbdd20aSAndroid Build Coastguard Workerimport re
32*6dbdd20aSAndroid Build Coastguard Workerimport sys
33*6dbdd20aSAndroid Build Coastguard Workerimport subprocess
34*6dbdd20aSAndroid Build Coastguard Worker
35*6dbdd20aSAndroid Build Coastguard Worker# Note: PROJECT_ROOT is not accurate in bazel builds, where this script is
36*6dbdd20aSAndroid Build Coastguard Worker# executed in the bazel sandbox.
37*6dbdd20aSAndroid Build Coastguard WorkerPROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
38*6dbdd20aSAndroid Build Coastguard WorkerSCM_REV_NOT_AVAILABLE = 'N/A'
39*6dbdd20aSAndroid Build Coastguard Worker
40*6dbdd20aSAndroid Build Coastguard Worker
41*6dbdd20aSAndroid Build Coastguard Workerdef get_latest_release(changelog_path):
42*6dbdd20aSAndroid Build Coastguard Worker  """Returns a string like 'v9.0'.
43*6dbdd20aSAndroid Build Coastguard Worker
44*6dbdd20aSAndroid Build Coastguard Worker  It does so by searching the latest version mentioned in the CHANGELOG."""
45*6dbdd20aSAndroid Build Coastguard Worker  if not changelog_path:
46*6dbdd20aSAndroid Build Coastguard Worker    if os.path.exists('CHANGELOG'):
47*6dbdd20aSAndroid Build Coastguard Worker      changelog_path = 'CHANGELOG'
48*6dbdd20aSAndroid Build Coastguard Worker    else:
49*6dbdd20aSAndroid Build Coastguard Worker      changelog_path = os.path.join(PROJECT_ROOT, 'CHANGELOG')
50*6dbdd20aSAndroid Build Coastguard Worker  with open(changelog_path) as f:
51*6dbdd20aSAndroid Build Coastguard Worker    for line in f.readlines():
52*6dbdd20aSAndroid Build Coastguard Worker      m = re.match(r'^(v\d+[.]\d+)\s.*$', line)
53*6dbdd20aSAndroid Build Coastguard Worker      if m is not None:
54*6dbdd20aSAndroid Build Coastguard Worker        return m.group(1)
55*6dbdd20aSAndroid Build Coastguard Worker  raise Exception('Failed to fetch Perfetto version from %s' % changelog_path)
56*6dbdd20aSAndroid Build Coastguard Worker
57*6dbdd20aSAndroid Build Coastguard Worker
58*6dbdd20aSAndroid Build Coastguard Workerdef get_git_sha1(commitish):
59*6dbdd20aSAndroid Build Coastguard Worker  """Returns the SHA1 of the provided commit-ish"""
60*6dbdd20aSAndroid Build Coastguard Worker  commit_sha1 = SCM_REV_NOT_AVAILABLE
61*6dbdd20aSAndroid Build Coastguard Worker  git_dir = os.path.join(PROJECT_ROOT, '.git')
62*6dbdd20aSAndroid Build Coastguard Worker  if os.path.exists(git_dir):
63*6dbdd20aSAndroid Build Coastguard Worker    try:
64*6dbdd20aSAndroid Build Coastguard Worker      commit_sha1 = subprocess.check_output(['git', 'rev-parse', commitish],
65*6dbdd20aSAndroid Build Coastguard Worker                                            cwd=PROJECT_ROOT).strip().decode()
66*6dbdd20aSAndroid Build Coastguard Worker    except subprocess.CalledProcessError:
67*6dbdd20aSAndroid Build Coastguard Worker      pass
68*6dbdd20aSAndroid Build Coastguard Worker  return commit_sha1
69*6dbdd20aSAndroid Build Coastguard Worker
70*6dbdd20aSAndroid Build Coastguard Worker
71*6dbdd20aSAndroid Build Coastguard Workerdef write_if_unchanged(path, content):
72*6dbdd20aSAndroid Build Coastguard Worker  prev_content = None
73*6dbdd20aSAndroid Build Coastguard Worker  if os.path.exists(path):
74*6dbdd20aSAndroid Build Coastguard Worker    with open(path, 'r') as fprev:
75*6dbdd20aSAndroid Build Coastguard Worker      prev_content = fprev.read()
76*6dbdd20aSAndroid Build Coastguard Worker  if prev_content == content:
77*6dbdd20aSAndroid Build Coastguard Worker    return 0
78*6dbdd20aSAndroid Build Coastguard Worker  with open(path, 'w') as fout:
79*6dbdd20aSAndroid Build Coastguard Worker    fout.write(content)
80*6dbdd20aSAndroid Build Coastguard Worker
81*6dbdd20aSAndroid Build Coastguard Worker
82*6dbdd20aSAndroid Build Coastguard Workerdef main():
83*6dbdd20aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
84*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--check_git', action='store_true')
85*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
86*6dbdd20aSAndroid Build Coastguard Worker      '--no_git',
87*6dbdd20aSAndroid Build Coastguard Worker      action='store_true',
88*6dbdd20aSAndroid Build Coastguard Worker      help='Skips running git rev-parse, emits only the version from CHANGELOG')
89*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--cpp_out', help='Path of the generated .h file.')
90*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--ts_out', help='Path of the generated .ts file.')
91*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--stdout', help='Write to stdout', action='store_true')
92*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--changelog', help='Path to CHANGELOG.')
93*6dbdd20aSAndroid Build Coastguard Worker  args = parser.parse_args()
94*6dbdd20aSAndroid Build Coastguard Worker
95*6dbdd20aSAndroid Build Coastguard Worker  if args.check_git:
96*6dbdd20aSAndroid Build Coastguard Worker    has_git = os.path.exists(os.path.join(PROJECT_ROOT, '.git', 'HEAD'))
97*6dbdd20aSAndroid Build Coastguard Worker    print('1' if has_git else '0')
98*6dbdd20aSAndroid Build Coastguard Worker    return 0
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Worker  release = get_latest_release(args.changelog)
101*6dbdd20aSAndroid Build Coastguard Worker
102*6dbdd20aSAndroid Build Coastguard Worker  if args.no_git:
103*6dbdd20aSAndroid Build Coastguard Worker    head_sha1 = SCM_REV_NOT_AVAILABLE
104*6dbdd20aSAndroid Build Coastguard Worker  else:
105*6dbdd20aSAndroid Build Coastguard Worker    head_sha1 = get_git_sha1('HEAD')  # SCM_REV_NOT_AVAILABLE on failure.
106*6dbdd20aSAndroid Build Coastguard Worker
107*6dbdd20aSAndroid Build Coastguard Worker  if head_sha1 == SCM_REV_NOT_AVAILABLE:
108*6dbdd20aSAndroid Build Coastguard Worker    version = release  # e.g., 'v9.0'.
109*6dbdd20aSAndroid Build Coastguard Worker  else:
110*6dbdd20aSAndroid Build Coastguard Worker    sha1_abbrev = head_sha1[:9]
111*6dbdd20aSAndroid Build Coastguard Worker    version = f'{release}-{sha1_abbrev}'  # e.g., 'v9.0-adeadbeef'.
112*6dbdd20aSAndroid Build Coastguard Worker
113*6dbdd20aSAndroid Build Coastguard Worker  if args.cpp_out:
114*6dbdd20aSAndroid Build Coastguard Worker    guard = '%s_' % args.cpp_out.upper()
115*6dbdd20aSAndroid Build Coastguard Worker    guard = re.sub(r'[^\w]', '_', guard)
116*6dbdd20aSAndroid Build Coastguard Worker    lines = []
117*6dbdd20aSAndroid Build Coastguard Worker    lines.append('// Generated by %s' % os.path.basename(__file__))
118*6dbdd20aSAndroid Build Coastguard Worker    lines.append('')
119*6dbdd20aSAndroid Build Coastguard Worker    lines.append('#ifndef %s' % guard)
120*6dbdd20aSAndroid Build Coastguard Worker    lines.append('#define %s' % guard)
121*6dbdd20aSAndroid Build Coastguard Worker    lines.append('')
122*6dbdd20aSAndroid Build Coastguard Worker    lines.append('#define PERFETTO_VERSION_STRING() "%s"' % version)
123*6dbdd20aSAndroid Build Coastguard Worker    lines.append('#define PERFETTO_VERSION_SCM_REVISION() "%s"' % head_sha1)
124*6dbdd20aSAndroid Build Coastguard Worker    lines.append('')
125*6dbdd20aSAndroid Build Coastguard Worker    lines.append('#endif  // %s' % guard)
126*6dbdd20aSAndroid Build Coastguard Worker    lines.append('')
127*6dbdd20aSAndroid Build Coastguard Worker    content = '\n'.join(lines)
128*6dbdd20aSAndroid Build Coastguard Worker    write_if_unchanged(args.cpp_out, content)
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard Worker  if args.ts_out:
131*6dbdd20aSAndroid Build Coastguard Worker    lines = []
132*6dbdd20aSAndroid Build Coastguard Worker    lines.append('export const VERSION = "%s";' % version)
133*6dbdd20aSAndroid Build Coastguard Worker    lines.append('export const SCM_REVISION = "%s";' % head_sha1)
134*6dbdd20aSAndroid Build Coastguard Worker    content = '\n'.join(lines)
135*6dbdd20aSAndroid Build Coastguard Worker    write_if_unchanged(args.ts_out, content)
136*6dbdd20aSAndroid Build Coastguard Worker
137*6dbdd20aSAndroid Build Coastguard Worker  if args.stdout:
138*6dbdd20aSAndroid Build Coastguard Worker    print(version)
139*6dbdd20aSAndroid Build Coastguard Worker
140*6dbdd20aSAndroid Build Coastguard Worker
141*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__':
142*6dbdd20aSAndroid Build Coastguard Worker  sys.exit(main())
143