blob: db7cb89ac2f5f5ae1f84b50b634585a422d162d2 [file] [log] [blame]
Søren Gjessee6087bf2023-01-17 10:49:29 +01001#!/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
6import argparse
7import os
8import re
9try:
10 import resource
11except ImportError:
12 # Not a Unix system. Do what Gandalf tells you not to.
13 pass
14import shutil
15import subprocess
16import sys
17
18import utils
19
20ARCHIVE_BUCKET = 'r8-releases'
21REPO = 'https://github.com/google/smali'
22NO_DRYRUN_OUTPUT = object()
23
24def checkout(temp):
25 subprocess.check_call(['git', 'clone', REPO, temp])
26 return temp
27
Søren Gjessee6087bf2023-01-17 10:49:29 +010028def parse_options():
29 result = argparse.ArgumentParser(description='Release Smali')
Søren Gjessee6087bf2023-01-17 10:49:29 +010030 result.add_argument('--version',
Søren Gjessee6087bf2023-01-17 10:49:29 +010031 metavar=('<version>'),
32 help='The version of smali to archive.')
33 result.add_argument('--dry-run', '--dry_run',
34 nargs='?',
35 help='Build only, no upload.',
36 metavar='<output directory>',
37 default=None,
38 const=NO_DRYRUN_OUTPUT)
39 result.add_argument('--checkout',
40 help='Use existing checkout.')
41 return result.parse_args()
42
43
44def set_rlimit_to_max():
45 (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
46 resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))
47
48
49def Main():
50 options = parse_options()
51 if not utils.is_bot() and not options.dry_run:
52 raise Exception('You are not a bot, don\'t archive builds. '
53 + 'Use --dry-run to test locally')
54 if options.checkout and not options.dry_run:
55 raise Exception('Using local checkout is only allowed with --dry-run')
Ian Zerny6e65f712023-02-15 09:46:02 +010056 if not options.checkout and not options.version:
57 raise Exception('Option --version is required (when not using local checkout)')
Søren Gjessee6087bf2023-01-17 10:49:29 +010058
59 if utils.is_bot() and not utils.IsWindows():
60 set_rlimit_to_max()
61
62 with utils.TempDir() as temp:
63 # Resolve dry run location to support relative directories.
64 dry_run_output = None
65 if options.dry_run and options.dry_run != NO_DRYRUN_OUTPUT:
66 if not os.path.isdir(options.dry_run):
67 os.mkdir(options.dry_run)
68 dry_run_output = os.path.abspath(options.dry_run)
69
70 checkout_dir = options.checkout if options.checkout else checkout(temp)
71 with utils.ChangedWorkingDirectory(checkout_dir):
Ian Zerny6e65f712023-02-15 09:46:02 +010072 if options.version:
73 output = subprocess.check_output(['git', 'tag', '-l', options.version])
74 if len(output) == 0:
75 raise Exception(
76 'Repository does not have a release tag for version %s' % options.version)
77 subprocess.check_call(['git', 'checkout', options.version])
Søren Gjessee6087bf2023-01-17 10:49:29 +010078
79 # Find version from `build.gradle`.
80 for line in open(os.path.join('build.gradle'), 'r'):
81 result = re.match(
82 r'^version = \'(\d+)\.(\d+)\.(\d+)\'', line)
83 if result:
84 break
85 version = '%s.%s.%s' % (result.group(1), result.group(2), result.group(3))
Søren Gjesse401102a2023-01-27 09:12:33 +010086 if options.version and version != options.version:
87 message = 'version %s, expected version %s' % (version, options.version)
88 if (options.checkout):
89 raise Exception('Checkout %s has %s' % (options.checkout, message))
90 else:
Ian Zerny6e65f712023-02-15 09:46:02 +010091 raise Exception('Tag % has %s' % (options.version, message))
92
Søren Gjessee6087bf2023-01-17 10:49:29 +010093 print('Building version: %s' % version)
94
95 # Build release to local Maven repository.
96 m2 = os.path.join(temp, 'm2')
97 os.mkdir(m2)
98 subprocess.check_call(
Søren Gjesse401102a2023-01-27 09:12:33 +010099 ['./gradlew', '-Dmaven.repo.local=%s' % m2 , 'release', 'test', 'publishToMavenLocal'])
Søren Gjessee6087bf2023-01-17 10:49:29 +0100100 base = os.path.join('com', 'android', 'tools', 'smali')
101
102 # Check that the local maven repository only has the single version directory in
103 # each artifact directory.
104 for name in ['smali-util', 'smali-dexlib2', 'smali', 'smali-baksmali']:
105 dirnames = next(os.walk(os.path.join(m2, base, name)), (None, None, []))[1]
106 if not dirnames or len(dirnames) != 1 or dirnames[0] != version:
107 raise Exception('Found unexpected directory %s in %s' % (dirnames, name))
108
109 # Build an archive with the relevant content of the local maven repository.
110 m2_filtered = os.path.join(temp, 'm2_filtered')
111 shutil.copytree(m2, m2_filtered, ignore=shutil.ignore_patterns('maven-metadata-local.xml'))
112 maven_release_archive = shutil.make_archive(
113 'smali-maven-release-%s' % version, 'zip', m2_filtered, base)
114
115 # Collect names of the fat jars.
116 fat_jars = list(map(
117 lambda prefix: '%s-%s-fat.jar' % (prefix, version),
118 ['smali/build/libs/smali', 'baksmali/build/libs/baksmali']))
119
120 # Copy artifacts.
121 files = [maven_release_archive]
122 files.extend(fat_jars)
123 if options.dry_run:
124 if dry_run_output:
125 print('Dry run, not actually uploading. Copying to %s:' % dry_run_output)
126 for file in files:
127 destination = os.path.join(dry_run_output, os.path.basename(file))
128 shutil.copyfile(file, destination)
129 print(" %s" % destination)
130 else:
131 print('Dry run, not actually uploading. Generated files:')
132 for file in files:
133 print(" %s" % os.path.basename(file))
134 else:
135 destination_prefix = 'gs://%s/smali/%s' % (ARCHIVE_BUCKET, version)
136 if utils.cloud_storage_exists(destination_prefix):
137 raise Exception('Target archive directory %s already exists' % destination_prefix)
138 for file in files:
139 destination = '%s/%s' % (destination_prefix, os.path.basename(file))
140 if utils.cloud_storage_exists(destination):
141 raise Exception('Target %s already exists' % destination)
142 utils.upload_file_to_cloud_storage(file, destination)
143 public_url = 'https://storage.googleapis.com/%s/smali/%s' % (ARCHIVE_BUCKET, version)
144 print('Artifacts available at: %s' % public_url)
145
146 print("Done!")
147
148if __name__ == '__main__':
149 sys.exit(Main())