blob: dd02a69e9f3e9681edeaf634bca4a1b1aa8070a7 [file] [log] [blame]
Primiano Tucci34bc5592021-02-19 17:53:36 +01001#!/usr/bin/env python3
Primiano Tucciec590132020-11-16 14:16:44 +01002# Copyright (C) 2020 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""
16Writes the perfetto_version{.gen.h, .ts} files.
17
18This tool is run as part of a genrule from GN, SoonG and Bazel builds. It
19generates a source header (or in the case of --ts_out a TypeScript file) that
20contains:
21- The version number (e.g. v9.0) obtained parsing the CHANGELOG file.
22- The git HEAD's commit-ish (e.g. 6b330b772b0e973f79c70ba2e9bb2b0110c6715d)
23- The number of CLs from the release tag to HEAD.
24
25The latter is concatenated to the version number to distinguish builds made
26fully from release tags (e.g., v9.0.0) vs builds made from the main branch which
27are N cls ahead of the latest monthly release (e.g., v9.0.42).
28"""
29
30import argparse
31import os
32import re
33import sys
34import subprocess
35
36# Note: PROJECT_ROOT is not accurate in bazel builds, where this script is
37# executed in the bazel sandbox.
38PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
39SCM_REV_NOT_AVAILABLE = 'N/A'
40
41
Primiano Tuccif0ed1d42020-11-18 16:30:18 +010042def get_latest_release(changelog_path):
Primiano Tucciec590132020-11-16 14:16:44 +010043 """Returns a string like 'v9.0'.
44
45 It does so by searching the latest version mentioned in the CHANGELOG."""
Primiano Tuccif0ed1d42020-11-18 16:30:18 +010046 if not changelog_path:
47 if os.path.exists('CHANGELOG'):
48 changelog_path = 'CHANGELOG'
49 else:
50 changelog_path = os.path.join(PROJECT_ROOT, 'CHANGELOG')
Primiano Tucciec590132020-11-16 14:16:44 +010051 with open(changelog_path) as f:
52 for line in f.readlines():
53 m = re.match('^(v\d+[.]\d+)\s.*$', line)
54 if m is not None:
55 return m.group(1)
56 raise Exception('Failed to fetch Perfetto version from %s' % changelog_path)
57
58
59def get_git_info(last_release_tag):
60 """Returns a tuple ('deadbeef', '1234').
61
62 The first value is the SHA1 of the HEAD. The second is the number of CLs from
63 the passed |last_release_tag| to HEAD."""
64 commit_sha1 = SCM_REV_NOT_AVAILABLE
65 commits_since_release = ''
66 git_dir = os.path.join(PROJECT_ROOT, '.git')
67 if os.path.exists(git_dir):
68 try:
69 commit_sha1 = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
70 cwd=PROJECT_ROOT).strip().decode()
71 with open(os.devnull, 'wb') as devnull:
72 commits_since_release = subprocess.check_output(
73 [
74 'git', 'rev-list', '--count',
75 'refs/tags/%s..HEAD' % last_release_tag
76 ],
77 cwd=PROJECT_ROOT,
78 stderr=devnull).strip().decode()
79 except subprocess.CalledProcessError:
80 pass
81
82 return (commit_sha1, commits_since_release)
83
84
85def write_if_unchanged(path, content):
86 prev_content = None
87 if os.path.exists(path):
88 with open(path, 'r') as fprev:
89 prev_content = fprev.read()
90 if prev_content == content:
91 return 0
92 with open(path, 'w') as fout:
93 fout.write(content)
94
95
96def main():
97 parser = argparse.ArgumentParser()
98 parser.add_argument(
99 '--no_git',
100 action='store_true',
101 help='Skips running git rev-parse, emits only the version from CHANGELOG')
102 parser.add_argument('--cpp_out', help='Path of the generated .h file.')
103 parser.add_argument('--ts_out', help='Path of the generated .ts file.')
Primiano Tucci7eead2e2021-02-16 11:46:04 +0100104 parser.add_argument('--stdout', help='Write to stdout', action='store_true')
Primiano Tuccif0ed1d42020-11-18 16:30:18 +0100105 parser.add_argument('--changelog', help='Path to CHANGELOG.')
Primiano Tucciec590132020-11-16 14:16:44 +0100106 args = parser.parse_args()
107
Primiano Tuccif0ed1d42020-11-18 16:30:18 +0100108 release = get_latest_release(args.changelog)
Primiano Tucciec590132020-11-16 14:16:44 +0100109 if args.no_git:
110 git_sha1, commits_since_release = (SCM_REV_NOT_AVAILABLE, '')
111 else:
112 git_sha1, commits_since_release = get_git_info(release)
113
114 # Try to compute the number of commits since the last release. This can fail
115 # in some environments (e.g. in android builds) because the bots pull only
116 # the main branch and don't pull the whole list of tags.
117 if commits_since_release:
118 version = '%s.%s' % (release, commits_since_release) # e.g., 'v9.0.42'.
119 else:
120 version = release # e.g., 'v9.0'.
121
122 if args.cpp_out:
123 guard = '%s_' % args.cpp_out.upper()
124 guard = re.sub(r'[^\w]', '_', guard)
125 lines = []
Florian Mayer5ed03d12021-04-19 18:07:52 +0100126 lines.append('// Generated by %s' % os.path.basename(__file__))
Primiano Tucciec590132020-11-16 14:16:44 +0100127 lines.append('')
128 lines.append('#ifndef %s' % guard)
129 lines.append('#define %s' % guard)
130 lines.append('')
131 lines.append('#define PERFETTO_VERSION_STRING() "%s"' % version)
132 lines.append('#define PERFETTO_VERSION_SCM_REVISION() "%s"' % git_sha1)
133 lines.append('')
134 lines.append('#endif // %s' % guard)
135 lines.append('')
136 content = '\n'.join(lines)
137 write_if_unchanged(args.cpp_out, content)
138
139 if args.ts_out:
140 lines = []
141 lines.append('export const VERSION = "%s";' % version)
142 lines.append('export const SCM_REVISION = "%s";' % git_sha1)
143 content = '\n'.join(lines)
144 write_if_unchanged(args.ts_out, content)
145
Primiano Tucci7eead2e2021-02-16 11:46:04 +0100146 if args.stdout:
147 print(version)
148
Primiano Tucciec590132020-11-16 14:16:44 +0100149
150if __name__ == '__main__':
151 sys.exit(main())