Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (C) 2017 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 | |
| 16 | import argparse |
| 17 | import hashlib |
| 18 | import logging |
| 19 | import os |
| 20 | import shutil |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 21 | import subprocess |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 22 | import sys |
| 23 | import urllib |
| 24 | import zipfile |
| 25 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 26 | from collections import namedtuple |
| 27 | |
Primiano Tucci | 636ede1 | 2017-10-30 16:03:07 +0000 | [diff] [blame] | 28 | # When adding a new git dependency here please also add a corresponding entry in |
| 29 | # .travis.yml under the "cache:" section. |
| 30 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 31 | # Dependencies required to build code on the host or when targeting desktop OS. |
| 32 | BUILD_DEPS_HOST = [ |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 33 | # GN |
| 34 | ('buildtools/mac/gn', |
| 35 | 'https://storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b', |
| 36 | 'c2c934d4dda1f470a6511b1015dda9a9fb1ce50b', |
| 37 | 'darwin' |
| 38 | ), |
| 39 | ('buildtools/linux64/gn', |
| 40 | 'https://storage.googleapis.com/chromium-gn/b53fa13e950948c6f9a062189b76b34a9610281f', |
| 41 | 'b53fa13e950948c6f9a062189b76b34a9610281f', |
| 42 | 'linux2' |
| 43 | ), |
| 44 | |
Primiano Tucci | 104bd6d | 2017-10-12 00:10:24 +0200 | [diff] [blame] | 45 | # clang-format |
| 46 | ('buildtools/mac/clang-format', |
| 47 | 'https://storage.googleapis.com/chromium-clang-format/0679b295e2ce2fce7919d1e8d003e497475f24a3', |
| 48 | '0679b295e2ce2fce7919d1e8d003e497475f24a3', |
| 49 | 'darwin' |
| 50 | ), |
| 51 | ('buildtools/linux64/clang-format', |
| 52 | 'https://storage.googleapis.com/chromium-clang-format/5349d1954e17f6ccafb6e6663b0f13cdb2bb33c8', |
| 53 | '5349d1954e17f6ccafb6e6663b0f13cdb2bb33c8', |
| 54 | 'linux2' |
| 55 | ), |
| 56 | # Keep the SHA1 in sync with |clang_format_rev| in chromium //buildtools/DEPS. |
| 57 | ('buildtools/clang_format/script', |
| 58 | 'https://chromium.googlesource.com/chromium/llvm-project/cfe/tools/clang-format.git', |
| 59 | '0653eee0c81ea04715c635dd0885e8096ff6ba6d', |
| 60 | 'all' |
| 61 | ), |
| 62 | |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 63 | # Ninja |
| 64 | ('buildtools/mac/ninja', |
| 65 | 'https://storage.googleapis.com/fuchsia-build/fuchsia/ninja/mac/a1db595e824c50cf565fbf0af2437fd91b7babf4', |
| 66 | 'a1db595e824c50cf565fbf0af2437fd91b7babf4', |
| 67 | 'darwin' |
| 68 | ), |
| 69 | ('buildtools/linux64/ninja', |
| 70 | 'https://storage.googleapis.com/fuchsia-build/fuchsia/ninja/linux64/d35b36c84a09f7e38b25947cafada10e8bf835bc', |
| 71 | 'd35b36c84a09f7e38b25947cafada10e8bf835bc', |
| 72 | 'linux2' |
| 73 | ), |
| 74 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 75 | # Keep in sync with Android's //external/googletest/README.version. |
| 76 | ('buildtools/googletest.zip', |
| 77 | 'https://github.com/google/googletest/archive/ff07a5de0e81580547f1685e101194ed1a4fcd56.zip', |
| 78 | 'c7edec7d7e6db1fc37a20710de9c4d89e3a3893b', |
| 79 | 'all' |
| 80 | ), |
| 81 | |
| 82 | # Keep in sync with Android's //external/protobuf/README.version. |
| 83 | ('buildtools/protobuf.zip', |
| 84 | 'https://github.com/google/protobuf/releases/download/v3.0.0-beta-3/protobuf-cpp-3.0.0-beta-3.zip', |
| 85 | '3caec60aa9d8eefc8c3c3201b6b8ca19935edb89', |
| 86 | 'all' |
| 87 | ), |
| 88 | |
| 89 | # libc++ and libc++abi, for clang msan that require rebuilding the C++ lib |
| 90 | # from sources. Keep the SHA1s in sync with Chrome's src/buildtools/DEPS. |
| 91 | ('buildtools/libcxx', |
| 92 | 'https://chromium.googlesource.com/chromium/llvm-project/libcxx.git', |
| 93 | '3a07dd740be63878167a0ea19fe81869954badd7', |
| 94 | 'all' |
| 95 | ), |
| 96 | ('buildtools/libcxxabi', |
| 97 | 'https://chromium.googlesource.com/chromium/llvm-project/libcxxabi.git', |
| 98 | '4072e8fd76febee37f60aeda76d6d9f5e3791daa', |
| 99 | 'all' |
| 100 | ), |
Primiano Tucci | 7278dea | 2017-10-31 11:50:32 +0000 | [diff] [blame] | 101 | ('buildtools/libunwind', |
| 102 | 'https://chromium.googlesource.com/external/llvm.org/libunwind.git', |
| 103 | '41f982e5887185b904a456e20dfcd58e6be6cc19', |
| 104 | 'all' |
| 105 | ), |
Hector Dearman | 88a1011 | 2017-10-12 11:07:10 +0100 | [diff] [blame] | 106 | |
| 107 | # Benchmarking tool. |
| 108 | ('buildtools/benchmark.zip', |
| 109 | 'https://github.com/google/benchmark/archive/v1.2.0.zip', |
| 110 | '553b6bfa59c63f15c54cfd8c5122b0f7f84469af', |
| 111 | 'all' |
| 112 | ), |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 113 | ] |
| 114 | |
| 115 | # Dependencies required to build Android code. |
| 116 | # URLs and SHA1s taken from: |
| 117 | # - https://dl.google.com/android/repository/repository-11.xml |
| 118 | # - https://dl.google.com/android/repository/sys-img/android/sys-img.xml |
| 119 | BUILD_DEPS_ANDROID = [ |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 120 | # Android NDK |
| 121 | ('buildtools/ndk.zip', |
| 122 | 'https://dl.google.com/android/repository/android-ndk-r15c-darwin-x86_64.zip', |
| 123 | 'ea4b5d76475db84745aa8828000d009625fc1f98', |
| 124 | 'darwin' |
| 125 | ), |
| 126 | ('buildtools/ndk.zip', |
| 127 | 'https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip', |
| 128 | '0bf02d4e8b85fd770fd7b9b2cdec57f9441f27a2', |
| 129 | 'linux2' |
| 130 | ), |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 131 | ] |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 132 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 133 | # Dependencies required to run Android tests. |
| 134 | TEST_DEPS_ANDROID = [ |
| 135 | # tools.zip contains the emulator binaries. |
| 136 | ('buildtools/android_sdk/tools.zip', |
| 137 | 'https://dl.google.com/android/repository/tools_r25.2.5-macosx.zip', |
| 138 | 'd2168d963ac5b616e3d3ddaf21511d084baf3659', |
| 139 | 'darwin' |
| 140 | ), |
| 141 | ('buildtools/android_sdk/tools.zip', |
| 142 | 'https://dl.google.com/android/repository/tools_r25.2.5-linux.zip', |
| 143 | '72df3aa1988c0a9003ccdfd7a13a7b8bd0f47fc1', |
| 144 | 'linux2' |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 145 | ), |
| 146 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 147 | # platform-tools.zip contains adb binaries. |
| 148 | ('buildtools/android_sdk/platform-tools.zip', |
| 149 | 'https://dl.google.com/android/repository/platform-tools_r26.0.0-darwin.zip', |
| 150 | 'e75b6137dc444f777eb02f44a6d9819b3aabff82', |
| 151 | 'darwin' |
| 152 | ), |
| 153 | ('buildtools/android_sdk/platform-tools.zip', |
| 154 | 'https://dl.google.com/android/repository/platform-tools_r26.0.0-linux.zip', |
| 155 | '00de8a6631405b617c10f68cd11ff2e1cd528e23', |
| 156 | 'linux2' |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 157 | ), |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 158 | |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 159 | # Android emulator images. |
| 160 | ('buildtools/android_sdk/system-images/android-24/default/armeabi-v7a.zip', |
| 161 | 'https://dl.google.com/android/repository/sys-img/android/armeabi-v7a-24_r07.zip', |
| 162 | '3454546b4eed2d6c3dd06d47757d6da9f4176033', |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 163 | 'all' |
| 164 | ), |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 165 | ('buildtools/android_sdk/system-images/android-24/default/arm64-v8a.zip', |
| 166 | 'https://dl.google.com/android/repository/sys-img/android/arm64-v8a-24_r07.zip', |
| 167 | 'e8ab2e49e4efe4b064232b33b5eeaded61437d7f', |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 168 | 'all' |
| 169 | ), |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 170 | ] |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 171 | |
| 172 | ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 173 | |
| 174 | |
| 175 | def ReadFile(path): |
| 176 | if not os.path.exists(path): |
| 177 | return None |
| 178 | with open(path) as f: |
| 179 | return f.read().strip() |
| 180 | |
| 181 | |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 182 | def MkdirRecursive(path): |
| 183 | # Works with both relative and absolute paths |
| 184 | cwd = '/' if path.startswith('/') else ROOT_DIR |
| 185 | for part in path.split('/'): |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 186 | cwd = os.path.join(cwd, part) |
| 187 | if not os.path.exists(cwd): |
| 188 | os.makedirs(cwd) |
| 189 | else: |
| 190 | assert(os.path.isdir(cwd)) |
| 191 | |
| 192 | |
| 193 | def HashLocalFile(path): |
| 194 | if not os.path.exists(path): |
| 195 | return None |
| 196 | with open(path, 'rb') as f: |
| 197 | return hashlib.sha1(f.read()).hexdigest() |
| 198 | |
| 199 | |
| 200 | def ExtractZipfilePreservePermissions(zf, info, path): |
| 201 | zf.extract(info.filename, path=path) |
| 202 | target_path = os.path.join(path, info.filename) |
| 203 | min_acls = 0o755 if info.filename.endswith('/') else 0o644 |
| 204 | os.chmod(target_path, (info.external_attr >> 16L) | min_acls) |
| 205 | |
| 206 | |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 207 | def IsGitRepoCheckoutOutAtRevision(path, revision): |
| 208 | return ReadFile(os.path.join(path, '.git', 'HEAD')) == revision |
| 209 | |
| 210 | |
| 211 | def CheckoutGitRepo(path, git_url, revision): |
| 212 | if IsGitRepoCheckoutOutAtRevision(path, revision): |
| 213 | return |
| 214 | if os.path.exists(path): |
| 215 | shutil.rmtree(path) |
| 216 | MkdirRecursive(path) |
| 217 | logging.info('Fetching %s @ %s into %s', git_url, revision, path) |
| 218 | subprocess.check_call(['git', 'clone', git_url, path], cwd=path) |
| 219 | subprocess.check_call(['git', 'checkout', revision, '--quiet'], cwd=path) |
| 220 | assert(IsGitRepoCheckoutOutAtRevision(path, revision)) |
| 221 | |
| 222 | |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 223 | def Main(): |
| 224 | parser = argparse.ArgumentParser() |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 225 | parser.add_argument('--no-android', action='store_true') |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 226 | args = parser.parse_args() |
Primiano Tucci | d775045 | 2017-09-29 14:38:51 +0100 | [diff] [blame] | 227 | deps = BUILD_DEPS_HOST |
| 228 | if not args.no_android: |
| 229 | deps += BUILD_DEPS_ANDROID + TEST_DEPS_ANDROID |
| 230 | for rel_path, url, expected_sha1, platform in deps: |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 231 | if platform != 'all' and platform != sys.platform: |
| 232 | continue |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 233 | local_path = os.path.join(ROOT_DIR, rel_path) |
Primiano Tucci | 0825bc8 | 2017-09-28 18:50:23 +0100 | [diff] [blame] | 234 | if url.endswith('.git'): |
| 235 | CheckoutGitRepo(local_path, url, expected_sha1) |
| 236 | continue |
Primiano Tucci | ae2879e | 2017-09-27 11:02:09 +0900 | [diff] [blame] | 237 | is_zip = local_path.lower().endswith('.zip') |
| 238 | zip_target_dir = local_path[:-4] if is_zip else None |
| 239 | zip_dir_stamp = os.path.join(zip_target_dir, '.stamp') if is_zip else None |
| 240 | |
| 241 | if ((not is_zip and HashLocalFile(local_path) == expected_sha1) or |
| 242 | (is_zip and ReadFile(zip_dir_stamp) == expected_sha1)): |
| 243 | continue |
| 244 | MkdirRecursive(os.path.dirname(rel_path)) |
| 245 | if HashLocalFile(local_path) != expected_sha1: |
| 246 | download_path = local_path + '.tmp' |
| 247 | logging.info('Downloading %s from %s', local_path, url) |
| 248 | urllib.urlretrieve(url, download_path) |
| 249 | os.chmod(download_path, 0o755) |
| 250 | if (HashLocalFile(download_path) != expected_sha1): |
| 251 | os.remove(download_path) |
| 252 | logging.fatal('SHA1 mismatch for %s', download_path) |
| 253 | return 1 |
| 254 | os.rename(download_path, local_path) |
| 255 | assert(HashLocalFile(local_path) == expected_sha1) |
| 256 | |
| 257 | if is_zip: |
| 258 | logging.info('Extracting %s into %s' % (local_path, zip_target_dir)) |
| 259 | assert(os.path.commonprefix((ROOT_DIR, zip_target_dir)) == ROOT_DIR) |
| 260 | if os.path.exists(zip_target_dir): |
| 261 | logging.info('Deleting stale dir %s' % zip_target_dir) |
| 262 | shutil.rmtree(zip_target_dir) |
| 263 | with zipfile.ZipFile(local_path, 'r') as zf: |
| 264 | for info in zf.infolist(): |
| 265 | ExtractZipfilePreservePermissions(zf, info, zip_target_dir) |
| 266 | |
| 267 | # If the zip contains one root folder, rebase one level up moving all |
| 268 | # its sub files and folders inside |target_dir|. |
| 269 | subdir = os.listdir(zip_target_dir) |
| 270 | if len(subdir) == 1: |
| 271 | subdir = os.path.join(zip_target_dir, subdir[0]) |
| 272 | if os.path.isdir(subdir): |
| 273 | for subf in os.listdir(subdir): |
| 274 | shutil.move(os.path.join(subdir,subf), zip_target_dir) |
| 275 | os.rmdir(subdir) |
| 276 | with open(zip_dir_stamp, 'w') as stamp_file: |
| 277 | stamp_file.write(expected_sha1) |
| 278 | os.remove(local_path) |
| 279 | |
| 280 | |
| 281 | if __name__ == '__main__': |
| 282 | logging.basicConfig(level=logging.INFO) |
| 283 | sys.exit(Main()) |