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 |
| 21 | import sys |
| 22 | import urllib |
| 23 | import zipfile |
| 24 | |
| 25 | PREBUILTS = ( |
| 26 | # GN |
| 27 | ('buildtools/mac/gn', |
| 28 | 'https://storage.googleapis.com/chromium-gn/c2c934d4dda1f470a6511b1015dda9a9fb1ce50b', |
| 29 | 'c2c934d4dda1f470a6511b1015dda9a9fb1ce50b', |
| 30 | 'darwin' |
| 31 | ), |
| 32 | ('buildtools/linux64/gn', |
| 33 | 'https://storage.googleapis.com/chromium-gn/b53fa13e950948c6f9a062189b76b34a9610281f', |
| 34 | 'b53fa13e950948c6f9a062189b76b34a9610281f', |
| 35 | 'linux2' |
| 36 | ), |
| 37 | |
| 38 | # Ninja |
| 39 | ('buildtools/mac/ninja', |
| 40 | 'https://storage.googleapis.com/fuchsia-build/fuchsia/ninja/mac/a1db595e824c50cf565fbf0af2437fd91b7babf4', |
| 41 | 'a1db595e824c50cf565fbf0af2437fd91b7babf4', |
| 42 | 'darwin' |
| 43 | ), |
| 44 | ('buildtools/linux64/ninja', |
| 45 | 'https://storage.googleapis.com/fuchsia-build/fuchsia/ninja/linux64/d35b36c84a09f7e38b25947cafada10e8bf835bc', |
| 46 | 'd35b36c84a09f7e38b25947cafada10e8bf835bc', |
| 47 | 'linux2' |
| 48 | ), |
| 49 | |
| 50 | # Android NDK |
| 51 | ('buildtools/ndk.zip', |
| 52 | 'https://dl.google.com/android/repository/android-ndk-r15c-darwin-x86_64.zip', |
| 53 | 'ea4b5d76475db84745aa8828000d009625fc1f98', |
| 54 | 'darwin' |
| 55 | ), |
| 56 | ('buildtools/ndk.zip', |
| 57 | 'https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip', |
| 58 | '0bf02d4e8b85fd770fd7b9b2cdec57f9441f27a2', |
| 59 | 'linux2' |
| 60 | ), |
| 61 | |
| 62 | # Keep in sync with Android's //external/googletest/README.version . |
| 63 | ('buildtools/googletest.zip', |
| 64 | 'https://github.com/google/googletest/archive/ff07a5de0e81580547f1685e101194ed1a4fcd56.zip', |
| 65 | 'c7edec7d7e6db1fc37a20710de9c4d89e3a3893b', |
| 66 | 'all' |
| 67 | ), |
| 68 | |
| 69 | # Keep in sync with Android's //external/protobuf/README.version . |
| 70 | ('buildtools/protobuf.zip', |
| 71 | 'https://github.com/google/protobuf/releases/download/v3.0.0-beta-3/protobuf-cpp-3.0.0-beta-3.zip', |
| 72 | '3caec60aa9d8eefc8c3c3201b6b8ca19935edb89', |
| 73 | 'all' |
| 74 | ), |
| 75 | ) |
| 76 | |
| 77 | ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 78 | |
| 79 | |
| 80 | def ReadFile(path): |
| 81 | if not os.path.exists(path): |
| 82 | return None |
| 83 | with open(path) as f: |
| 84 | return f.read().strip() |
| 85 | |
| 86 | |
| 87 | def MkdirRecursive(rel_path): |
| 88 | cwd = ROOT_DIR |
| 89 | for part in rel_path.split('/'): |
| 90 | cwd = os.path.join(cwd, part) |
| 91 | if not os.path.exists(cwd): |
| 92 | os.makedirs(cwd) |
| 93 | else: |
| 94 | assert(os.path.isdir(cwd)) |
| 95 | |
| 96 | |
| 97 | def HashLocalFile(path): |
| 98 | if not os.path.exists(path): |
| 99 | return None |
| 100 | with open(path, 'rb') as f: |
| 101 | return hashlib.sha1(f.read()).hexdigest() |
| 102 | |
| 103 | |
| 104 | def ExtractZipfilePreservePermissions(zf, info, path): |
| 105 | zf.extract(info.filename, path=path) |
| 106 | target_path = os.path.join(path, info.filename) |
| 107 | min_acls = 0o755 if info.filename.endswith('/') else 0o644 |
| 108 | os.chmod(target_path, (info.external_attr >> 16L) | min_acls) |
| 109 | |
| 110 | |
| 111 | def Main(): |
| 112 | parser = argparse.ArgumentParser() |
| 113 | parser.add_argument('--skip', action='append', default=[]) |
| 114 | args = parser.parse_args() |
| 115 | skip_set = set(args.skip) |
| 116 | for rel_path, url, expected_sha1, platform in PREBUILTS: |
| 117 | if platform != 'all' and platform != sys.platform: |
| 118 | continue |
| 119 | if os.path.basename(rel_path) in skip_set: |
| 120 | logging.info('Skipping %s because of --skip cmdline arg', rel_path) |
| 121 | continue |
| 122 | local_path = os.path.join(ROOT_DIR, rel_path) |
| 123 | is_zip = local_path.lower().endswith('.zip') |
| 124 | zip_target_dir = local_path[:-4] if is_zip else None |
| 125 | zip_dir_stamp = os.path.join(zip_target_dir, '.stamp') if is_zip else None |
| 126 | |
| 127 | if ((not is_zip and HashLocalFile(local_path) == expected_sha1) or |
| 128 | (is_zip and ReadFile(zip_dir_stamp) == expected_sha1)): |
| 129 | continue |
| 130 | MkdirRecursive(os.path.dirname(rel_path)) |
| 131 | if HashLocalFile(local_path) != expected_sha1: |
| 132 | download_path = local_path + '.tmp' |
| 133 | logging.info('Downloading %s from %s', local_path, url) |
| 134 | urllib.urlretrieve(url, download_path) |
| 135 | os.chmod(download_path, 0o755) |
| 136 | if (HashLocalFile(download_path) != expected_sha1): |
| 137 | os.remove(download_path) |
| 138 | logging.fatal('SHA1 mismatch for %s', download_path) |
| 139 | return 1 |
| 140 | os.rename(download_path, local_path) |
| 141 | assert(HashLocalFile(local_path) == expected_sha1) |
| 142 | |
| 143 | if is_zip: |
| 144 | logging.info('Extracting %s into %s' % (local_path, zip_target_dir)) |
| 145 | assert(os.path.commonprefix((ROOT_DIR, zip_target_dir)) == ROOT_DIR) |
| 146 | if os.path.exists(zip_target_dir): |
| 147 | logging.info('Deleting stale dir %s' % zip_target_dir) |
| 148 | shutil.rmtree(zip_target_dir) |
| 149 | with zipfile.ZipFile(local_path, 'r') as zf: |
| 150 | for info in zf.infolist(): |
| 151 | ExtractZipfilePreservePermissions(zf, info, zip_target_dir) |
| 152 | |
| 153 | # If the zip contains one root folder, rebase one level up moving all |
| 154 | # its sub files and folders inside |target_dir|. |
| 155 | subdir = os.listdir(zip_target_dir) |
| 156 | if len(subdir) == 1: |
| 157 | subdir = os.path.join(zip_target_dir, subdir[0]) |
| 158 | if os.path.isdir(subdir): |
| 159 | for subf in os.listdir(subdir): |
| 160 | shutil.move(os.path.join(subdir,subf), zip_target_dir) |
| 161 | os.rmdir(subdir) |
| 162 | with open(zip_dir_stamp, 'w') as stamp_file: |
| 163 | stamp_file.write(expected_sha1) |
| 164 | os.remove(local_path) |
| 165 | |
| 166 | |
| 167 | if __name__ == '__main__': |
| 168 | logging.basicConfig(level=logging.INFO) |
| 169 | sys.exit(Main()) |