|  | #!/usr/bin/env python3 | 
|  | # Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file | 
|  | # for details. All rights reserved. Use of this source code is governed by a | 
|  | # BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | import argparse | 
|  | import jdk | 
|  | import json | 
|  | import os.path | 
|  | import re | 
|  | import subprocess | 
|  | import sys | 
|  | import urllib.request | 
|  |  | 
|  | import utils | 
|  |  | 
|  | # Grep match string for 'Version X.Y.Z[-dev]' | 
|  | VERSION_EXP = r'^Version [[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\(\|-dev\)$' | 
|  |  | 
|  | # R8 is located in the 'builder' library. | 
|  | AGP_MAVEN = "https://dl.google.com/android/maven2/com/android/tools/build/builder" | 
|  |  | 
|  |  | 
|  | def parse_options(): | 
|  | parser = argparse.ArgumentParser(description='Tag R8 Versions') | 
|  | parser.add_argument('--branch', | 
|  | help='The R8 branch to tag versions on, eg, origin/3.0') | 
|  | parser.add_argument('--agp', | 
|  | help='The AGP to compute the tag for, eg, 4.2.0-beta03') | 
|  | parser.add_argument('--use-push', | 
|  | default=False, | 
|  | action='store_true', | 
|  | help='To create the tag locally only.') | 
|  | parser.add_argument( | 
|  | '--dry-run', | 
|  | default=False, | 
|  | action='store_true', | 
|  | help='Print the state changing commands without running them.') | 
|  | return parser.parse_args() | 
|  |  | 
|  |  | 
|  | def run(options, cmd): | 
|  | print(' '.join(cmd)) | 
|  | if options.dry_run: | 
|  | return | 
|  | try: | 
|  | subprocess.check_call(cmd) | 
|  | except subprocess.CalledProcessError as e: | 
|  | print(e) | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | args = parse_options() | 
|  | if args.branch: | 
|  | tag_r8_branch(args.branch, args) | 
|  | elif args.agp: | 
|  | if (args.agp == 'all'): | 
|  | tag_all_agp_versions(args) | 
|  | else: | 
|  | tag_agp_version(args.agp, args) | 
|  | else: | 
|  | print("Should use a top-level option, such as --branch or --agp.") | 
|  | return 1 | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | def prepare_print_version(dist, temp): | 
|  | wrapper_file = os.path.join( | 
|  | utils.REPO_ROOT, | 
|  | 'src/main/java/com/android/tools/r8/utils/PrintR8Version.java') | 
|  | cmd = [ | 
|  | jdk.GetJavacExecutable(), | 
|  | wrapper_file, | 
|  | '-d', | 
|  | temp, | 
|  | '-cp', | 
|  | dist, | 
|  | ] | 
|  | utils.PrintCmd(cmd) | 
|  | subprocess.check_output(cmd) | 
|  | return temp | 
|  |  | 
|  | # Testing info: To delete a tag use | 
|  | # | 
|  | # gob-curl --request DELETE https://r8-review.git.corp.google.com/a/projects/r8/tags/<tag> | 
|  | # | 
|  | def gerrit_tag(args, tag, hash, description): | 
|  | data = json.dumps({ | 
|  | "message": description if description else tag, | 
|  | "revision": hash | 
|  | }) | 
|  | cmd = ' '.join([ | 
|  | 'gob-curl', | 
|  | '--header', | 
|  | '"Content-Type: application/json; charset=UTF-8"', | 
|  | '--request', | 
|  | 'PUT', | 
|  | '--data', | 
|  | "'{data}'".format(data=data), | 
|  | 'https://r8-review.git.corp.google.com/a/projects/r8/tags/{tag}'.format(tag=tag) | 
|  | ]) | 
|  | result = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | 
|  | print(result) | 
|  |  | 
|  |  | 
|  | def get_tag_info_on_origin(tag): | 
|  | output = subprocess.check_output( | 
|  | ['git', 'ls-remote', '--tags', 'origin', tag]).decode('utf-8') | 
|  | if len(output.strip()) == 0: | 
|  | return None | 
|  | return output | 
|  |  | 
|  |  | 
|  | def tag_all_agp_versions(args): | 
|  | with utils.TempDir() as temp: | 
|  | url = "%s/maven-metadata.xml" % AGP_MAVEN | 
|  | metadata = os.path.join(temp, "maven-metadata.xml") | 
|  | try: | 
|  | urllib.request.urlretrieve(url, metadata) | 
|  | except urllib.error.HTTPError as e: | 
|  | print('Could not find maven-metadata.xml for agp') | 
|  | print(e) | 
|  | return 1 | 
|  | with open(metadata, 'r') as file: | 
|  | data = file.read() | 
|  | pattern = r'<version>(.+)</version>' | 
|  | matches = re.findall(pattern, data) | 
|  | matches.reverse() | 
|  | for version in matches: | 
|  | print('Tagging agp version ' + version) | 
|  | tag_agp_version(version, args) | 
|  |  | 
|  |  | 
|  | def tag_agp_version(agp_version, args): | 
|  | tag = 'agp-%s' % agp_version | 
|  | result = get_tag_info_on_origin(tag) | 
|  | if result: | 
|  | print('Tag %s is already present' % tag) | 
|  | print(result) | 
|  | subprocess.call(['git', 'show', '--oneline', '-s', tag]) | 
|  | return 0 | 
|  | with utils.TempDir() as temp: | 
|  | url = "%s/%s/builder-%s.jar" % (AGP_MAVEN, agp_version, agp_version) | 
|  | jar = os.path.join(temp, "agp.jar") | 
|  | try: | 
|  | urllib.request.urlretrieve(url, jar) | 
|  | except urllib.error.HTTPError as e: | 
|  | print('Could not find jar for agp %s' % agp_version) | 
|  | print(e) | 
|  | return 1 | 
|  | print_version_helper = prepare_print_version(utils.R8_JAR, temp) | 
|  | output = subprocess.check_output([ | 
|  | jdk.GetJavaExecutable(), '-cp', | 
|  | ':'.join([jar, print_version_helper]), | 
|  | 'com.android.tools.r8.utils.PrintR8Version' | 
|  | ]).decode('utf-8') | 
|  | r8_version = output.split(' ')[0] | 
|  | cmd = ' '.join(['git', 'rev-list', '-n', '1', r8_version]) | 
|  | hash = subprocess.check_output(cmd, shell=True).decode('utf-8').strip() | 
|  | message = 'AGP version {version}'.format(version=agp_version) | 
|  | run(args, ['git', 'tag', '-f', tag, '-m', message, hash]) | 
|  | if args.use_push: | 
|  | run(args, [ | 
|  | 'git', 'push', '-o', 'push-justification=b/313360935', 'origin', tag | 
|  | ]) | 
|  | else: | 
|  | gerrit_tag(args, tag, hash, message) | 
|  |  | 
|  |  | 
|  | def tag_r8_branch(branch, args): | 
|  | if not branch.startswith('origin/'): | 
|  | print('Expected branch to start with origin/') | 
|  | return 1 | 
|  | output = subprocess.check_output( | 
|  | ['git', 'log', '--pretty=format:%H\t%s', '--grep', VERSION_EXP, | 
|  | branch]).decode('utf-8') | 
|  | for l in output.split('\n'): | 
|  | (hash, subject) = l.split('\t') | 
|  | m = re.search('Version (.+)', subject) | 
|  | if not m: | 
|  | print('Unable to find a version for line: %s' % l) | 
|  | continue | 
|  | version = m.group(1) | 
|  | result = get_tag_info_on_origin(version) | 
|  | if not result: | 
|  | message = 'Version {version}'.format(version=version) | 
|  | run(args, ['git', 'tag', '-a', version, '-m', message, hash]) | 
|  | if args.use_push: | 
|  | run(args, [ | 
|  | 'git', 'push', '-o', 'push-justification=b/313360935', 'origin', | 
|  | version | 
|  | ]) | 
|  | else: | 
|  | gerrit_tag(args, version, hash, message) | 
|  | if args.dry_run: | 
|  | print('Dry run complete. None of the above have been executed.') | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main()) |