Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file |
| 3 | # for details. All rights reserved. Use of this source code is governed by a |
| 4 | # BSD-style license that can be found in the LICENSE file. |
| 5 | |
| 6 | import argparse |
| 7 | import os |
| 8 | import re |
| 9 | try: |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 10 | import resource |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 11 | except ImportError: |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 12 | # Not a Unix system. Do what Gandalf tells you not to. |
| 13 | pass |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 14 | import shutil |
| 15 | import subprocess |
| 16 | import sys |
| 17 | |
| 18 | import utils |
| 19 | |
| 20 | ARCHIVE_BUCKET = 'r8-releases' |
| 21 | REPO = 'https://github.com/google/smali' |
| 22 | NO_DRYRUN_OUTPUT = object() |
| 23 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 24 | |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 25 | def checkout(temp): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 26 | subprocess.check_call(['git', 'clone', REPO, temp]) |
| 27 | return temp |
| 28 | |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 29 | |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 30 | def parse_options(): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 31 | result = argparse.ArgumentParser(description='Release Smali') |
| 32 | result.add_argument('--version', |
| 33 | metavar=('<version>'), |
| 34 | help='The version of smali to archive.') |
| 35 | result.add_argument('--dry-run', |
| 36 | '--dry_run', |
| 37 | nargs='?', |
| 38 | help='Build only, no upload.', |
| 39 | metavar='<output directory>', |
| 40 | default=None, |
| 41 | const=NO_DRYRUN_OUTPUT) |
| 42 | result.add_argument('--checkout', help='Use existing checkout.') |
| 43 | return result.parse_args() |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 44 | |
| 45 | |
| 46 | def set_rlimit_to_max(): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 47 | (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE) |
| 48 | resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard)) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 49 | |
| 50 | |
| 51 | def Main(): |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 52 | options = parse_options() |
| 53 | if not utils.is_bot() and not options.dry_run: |
| 54 | raise Exception('You are not a bot, don\'t archive builds. ' + |
| 55 | 'Use --dry-run to test locally') |
| 56 | if options.checkout and not options.dry_run: |
| 57 | raise Exception('Using local checkout is only allowed with --dry-run') |
| 58 | if not options.checkout and not options.version: |
| 59 | raise Exception( |
| 60 | 'Option --version is required (when not using local checkout)') |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 61 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 62 | if utils.is_bot() and not utils.IsWindows(): |
| 63 | set_rlimit_to_max() |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 64 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 65 | with utils.TempDir() as temp: |
| 66 | # Resolve dry run location to support relative directories. |
| 67 | dry_run_output = None |
| 68 | if options.dry_run and options.dry_run != NO_DRYRUN_OUTPUT: |
| 69 | if not os.path.isdir(options.dry_run): |
| 70 | os.mkdir(options.dry_run) |
| 71 | dry_run_output = os.path.abspath(options.dry_run) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 72 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 73 | checkout_dir = options.checkout if options.checkout else checkout(temp) |
| 74 | with utils.ChangedWorkingDirectory(checkout_dir): |
| 75 | if options.version: |
| 76 | output = subprocess.check_output( |
| 77 | ['git', 'tag', '-l', options.version]) |
| 78 | if len(output) == 0: |
| 79 | raise Exception( |
| 80 | 'Repository does not have a release tag for version %s' |
| 81 | % options.version) |
| 82 | subprocess.check_call(['git', 'checkout', options.version]) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 83 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 84 | # Find version from `build.gradle`. |
| 85 | for line in open(os.path.join('build.gradle'), 'r'): |
| 86 | result = re.match(r'^version = \'(\d+)\.(\d+)\.(\d+)\'', line) |
| 87 | if result: |
| 88 | break |
| 89 | version = '%s.%s.%s' % (result.group(1), result.group(2), |
| 90 | result.group(3)) |
| 91 | if options.version and version != options.version: |
| 92 | message = 'version %s, expected version %s' % (version, |
| 93 | options.version) |
| 94 | if (options.checkout): |
| 95 | raise Exception('Checkout %s has %s' % |
| 96 | (options.checkout, message)) |
| 97 | else: |
| 98 | raise Exception('Tag % has %s' % (options.version, message)) |
Ian Zerny | 6e65f71 | 2023-02-15 09:46:02 +0100 | [diff] [blame] | 99 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 100 | print('Building version: %s' % version) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 101 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 102 | # Build release to local Maven repository. |
| 103 | m2 = os.path.join(temp, 'm2') |
| 104 | os.mkdir(m2) |
| 105 | subprocess.check_call([ |
| 106 | './gradlew', |
| 107 | '-Dmaven.repo.local=%s' % m2, 'release', 'test', |
| 108 | 'publishToMavenLocal' |
| 109 | ]) |
| 110 | base = os.path.join('com', 'android', 'tools', 'smali') |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 111 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 112 | # Check that the local maven repository only has the single version directory in |
| 113 | # each artifact directory. |
| 114 | for name in [ |
| 115 | 'smali-util', 'smali-dexlib2', 'smali', 'smali-baksmali' |
| 116 | ]: |
| 117 | dirnames = next(os.walk(os.path.join(m2, base, name)), |
| 118 | (None, None, []))[1] |
| 119 | if not dirnames or len(dirnames) != 1 or dirnames[0] != version: |
| 120 | raise Exception('Found unexpected directory %s in %s' % |
| 121 | (dirnames, name)) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 122 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 123 | # Build an archive with the relevant content of the local maven repository. |
| 124 | m2_filtered = os.path.join(temp, 'm2_filtered') |
| 125 | shutil.copytree( |
| 126 | m2, |
| 127 | m2_filtered, |
| 128 | ignore=shutil.ignore_patterns('maven-metadata-local.xml')) |
| 129 | maven_release_archive = shutil.make_archive( |
| 130 | 'smali-maven-release-%s' % version, 'zip', m2_filtered, base) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 131 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 132 | # Collect names of the fat jars. |
| 133 | fat_jars = list( |
| 134 | map(lambda prefix: '%s-%s-fat.jar' % (prefix, version), |
| 135 | ['smali/build/libs/smali', 'baksmali/build/libs/baksmali'])) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 136 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 137 | # Copy artifacts. |
| 138 | files = [maven_release_archive] |
| 139 | files.extend(fat_jars) |
| 140 | if options.dry_run: |
| 141 | if dry_run_output: |
| 142 | print('Dry run, not actually uploading. Copying to %s:' % |
| 143 | dry_run_output) |
| 144 | for file in files: |
| 145 | destination = os.path.join(dry_run_output, |
| 146 | os.path.basename(file)) |
| 147 | shutil.copyfile(file, destination) |
| 148 | print(" %s" % destination) |
| 149 | else: |
| 150 | print('Dry run, not actually uploading. Generated files:') |
| 151 | for file in files: |
| 152 | print(" %s" % os.path.basename(file)) |
| 153 | else: |
| 154 | destination_prefix = 'gs://%s/smali/%s' % (ARCHIVE_BUCKET, |
| 155 | version) |
| 156 | if utils.cloud_storage_exists(destination_prefix): |
| 157 | raise Exception( |
| 158 | 'Target archive directory %s already exists' % |
| 159 | destination_prefix) |
| 160 | for file in files: |
| 161 | destination = '%s/%s' % (destination_prefix, |
| 162 | os.path.basename(file)) |
| 163 | if utils.cloud_storage_exists(destination): |
| 164 | raise Exception('Target %s already exists' % |
| 165 | destination) |
| 166 | utils.upload_file_to_cloud_storage(file, destination) |
| 167 | public_url = 'https://storage.googleapis.com/%s/smali/%s' % ( |
| 168 | ARCHIVE_BUCKET, version) |
| 169 | print('Artifacts available at: %s' % public_url) |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 170 | |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 171 | print("Done!") |
| 172 | |
Søren Gjesse | e6087bf | 2023-01-17 10:49:29 +0100 | [diff] [blame] | 173 | |
| 174 | if __name__ == '__main__': |
Christoffer Quist Adamsen | 2434a4d | 2023-10-16 11:29:03 +0200 | [diff] [blame] | 175 | sys.exit(Main()) |