Reland "Add version consistently in all build configs and UI"
This is a partial reland of r.android.com/1499116 and
r.android.com/1497878, % the changes that depend on .git
on Android. Turns out that was a bad idea because some bots
can build without it.
Change:
The script that generates the build version can already gracefully
deal with the absence of git. However I forgot the dependency on
.git/HEAD, which makes the build system fail.
For now, in order to avoid problems, this avoids any git
invocation on Android in-tree builds. A follow up CL will
try extending with libbuildversion as suggedted in the bug.
This reverts commit 9d15a2309a4f03d000bcf6d4d4dcba36a3df2916.
This reverts commit bb4bfb0665d16525868e94f941d87ae89c858eb3.
The first patchset is a plain re-revert (i.e. a plain reland).
The patchset on top show the delta from the original cl (for ease
of re-review)
Bug: 173245796
Change-Id: Icd2f7f2727313b9cdc11c6bfa93b67478ae77974
diff --git a/tools/write_version_header.py b/tools/write_version_header.py
new file mode 100755
index 0000000..7982f50
--- /dev/null
+++ b/tools/write_version_header.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+# 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 number of CLs from the release tag to HEAD.
+
+The latter is concatenated to the version number to distinguish builds made
+fully from release tags (e.g., v9.0.0) vs builds made from the main branch which
+are N cls ahead of the latest monthly release (e.g., v9.0.42).
+"""
+
+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():
+ """Returns a string like 'v9.0'.
+
+ It does so by searching the latest version mentioned in the CHANGELOG."""
+ 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_info(last_release_tag):
+ """Returns a tuple ('deadbeef', '1234').
+
+ The first value is the SHA1 of the HEAD. The second is the number of CLs from
+ the passed |last_release_tag| to HEAD."""
+ commit_sha1 = SCM_REV_NOT_AVAILABLE
+ commits_since_release = ''
+ git_dir = os.path.join(PROJECT_ROOT, '.git')
+ if os.path.exists(git_dir):
+ try:
+ commit_sha1 = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
+ cwd=PROJECT_ROOT).strip().decode()
+ with open(os.devnull, 'wb') as devnull:
+ commits_since_release = subprocess.check_output(
+ [
+ 'git', 'rev-list', '--count',
+ 'refs/tags/%s..HEAD' % last_release_tag
+ ],
+ cwd=PROJECT_ROOT,
+ stderr=devnull).strip().decode()
+ except subprocess.CalledProcessError:
+ pass
+
+ return (commit_sha1, commits_since_release)
+
+
+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(
+ '--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.')
+ args = parser.parse_args()
+
+ release = get_latest_release()
+ if args.no_git:
+ git_sha1, commits_since_release = (SCM_REV_NOT_AVAILABLE, '')
+ else:
+ git_sha1, commits_since_release = get_git_info(release)
+
+ # Try to compute the number of commits since the last release. This can fail
+ # in some environments (e.g. in android builds) because the bots pull only
+ # the main branch and don't pull the whole list of tags.
+ if commits_since_release:
+ version = '%s.%s' % (release, commits_since_release) # e.g., 'v9.0.42'.
+ else:
+ version = release # e.g., 'v9.0'.
+
+ if args.cpp_out:
+ guard = '%s_' % args.cpp_out.upper()
+ guard = re.sub(r'[^\w]', '_', guard)
+ lines = []
+ lines.append('// Generated by %s' % __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"' % git_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";' % git_sha1)
+ content = '\n'.join(lines)
+ write_if_unchanged(args.ts_out, content)
+
+
+if __name__ == '__main__':
+ sys.exit(main())