1#!/usr/bin/python3 2 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Updates libchrome. 18 19This script uprevs the libchrome library with newer Chromium code. 20How to use: 21 22Prepare your local Chromium repository with the target revision. 23$ cd external/libchrome 24$ python3 libchrome_tools/update_libchrome.py \ 25 --chromium_root=${PATH_TO_YOUR_LOCAL_CHROMIUM_REPO} 26 27This script does following things; 28- Clean existing libchrome code, except some manually created files and tools. 29- Copy necessary files from original Chromium repository. 30- Apply patches to the copied files, if necessary. 31""" 32 33 34import argparse 35import fnmatch 36import glob 37import os 38import re 39import shutil 40import subprocess 41 42 43_TOOLS_DIR = os.path.dirname(os.path.realpath(__file__)) 44_LIBCHROME_ROOT = os.path.dirname(_TOOLS_DIR) 45 46 47# Files in this list or in the directory listed here will be just copied. 48# Paths ends with '/' is interpreted as directory. 49_IMPORT_LIST = [ 50 'mojo/', 51 'third_party/ply/', 52 'third_party/markupsafe/', 53 'third_party/jinja2/', 54] 55 56# Files which are in the repository, but should not be imported from Chrome 57# repository. 58_IMPORT_BLACKLIST = [ 59 # Libchrome specific files. 60 '.gitignore', 61 'Android.bp', 62 'MODULE_LICENSE_BSD', 63 'NOTICE', 64 'OWNERS', 65 'SConstruct', 66 'libmojo.pc.in', 67 'testrunner.cc', 68 '*/DEPS', 69 70 # No Chromium OWNERS should be imported. 71 '*/OWNERS', 72 73 # libchrome_tools and soong are out of the update target. 74 'libchrome_tools/*', 75 'soong/*', 76 77 # No internal directories. 78 'mojo/internal/*', 79 80 # Those files should be generated. Please see also buildflag_header.patch. 81 'base/allocator/buildflags.h', 82 'base/android/java/src/org/chromium/base/BuildConfig.java', 83 'base/cfi_buildflags.h', 84 'base/debug/debugging_buildflags.h', 85 'base/memory/protected_memory_buildflags.h', 86 'base/synchronization/synchronization_buildflags.h', 87 'gen/*', 88 'ipc/ipc_buildflags.h', 89 90 # Blacklist several third party libraries; system libraries should be used. 91 'base/third_party/libevent/*', 92 'base/third_party/symbolize/*', 93 94 'testing/gmock/*', 95 'testing/gtest/*', 96 'third_party/ashmem/*', 97 'third_party/modp_b64/*', 98 'third_party/protobuf/*', 99] 100 101def _find_target_files(chromium_root): 102 """Returns target files to be upreved.""" 103 # Files in the repository should be updated. 104 output = subprocess.check_output( 105 ['git', 'ls-tree', '-r', '--name-only', '--full-name', 'HEAD'], 106 cwd=_LIBCHROME_ROOT).decode('utf-8') 107 108 # Files in _IMPORT_LIST are copied in the following section, so 109 # exclude them from candidates, here, so that files deleted in chromium 110 # repository will be deleted on update. 111 candidates = [ 112 path for path in output.splitlines() 113 if not any(path.startswith(import_path) for import_path in _IMPORT_LIST)] 114 115 # All files listed in _IMPORT_LIST should be imported, too. 116 for import_path in _IMPORT_LIST: 117 import_root = os.path.join(chromium_root, import_path) 118 119 # If it is a file, just add to the candidates. 120 if os.path.isfile(import_root): 121 candidates.append(import_path) 122 continue 123 124 # If it is a directory, traverse all files in the directory recursively 125 # and add all of them to candidates. 126 for dirpath, dirnames, filenames in os.walk(import_root): 127 for filename in filenames: 128 filepath = os.path.join(dirpath, filename) 129 candidates.append(os.path.relpath(filepath, chromium_root)) 130 131 # Apply blacklist. 132 exclude_pattern = re.compile('|'.join( 133 '(?:%s)' % fnmatch.translate(pattern) for pattern in _IMPORT_BLACKLIST)) 134 return [filepath for filepath in candidates 135 if not exclude_pattern.match(filepath)] 136 137 138def _clean_existing_dir(output_root): 139 """Removes existing libchrome files. 140 141 Args: 142 output_root: Path to the output directory. 143 """ 144 os.makedirs(output_root, mode=0o755, exist_ok=True) 145 for path in os.listdir(output_root): 146 target_path = os.path.join(output_root, path) 147 if (not os.path.isdir(target_path) or path in ('.git', 'libchrome_tools', 'soong')): 148 continue 149 shutil.rmtree(target_path) 150 151 152def _import_files(chromium_root, output_root): 153 """Copies files from Chromium repository into libchrome. 154 155 Args: 156 chromium_root: Path to the Chromium's repository. 157 output_root: Path to the output directory. 158 """ 159 for filepath in _find_target_files(chromium_root): 160 source_path = os.path.join(chromium_root, filepath) 161 target_path = os.path.join(output_root, filepath) 162 os.makedirs(os.path.dirname(target_path), mode=0o755, exist_ok=True) 163 shutil.copy2(source_path, target_path) 164 165 166def _apply_patch_files(patch_root, output_root): 167 """Applies patches. 168 169 libchrome needs some modification from Chromium repository, e.g. supporting 170 toolchain which is not used by Chrome, or using system library rather than 171 the library checked in the Chromium repository. 172 See each *.patch file in libchrome_tools/patch/ directory for details. 173 174 Args: 175 patch_root: Path to the directory containing patch files. 176 output_root: Path to the output directory. 177 """ 178 for patch_file in glob.iglob(os.path.join(patch_root, '*.patch')): 179 with open(patch_file, 'r') as f: 180 subprocess.check_call(['patch', '-p1'], stdin=f, cwd=output_root) 181 182 183def _parse_args(): 184 """Parses commandline arguments.""" 185 parser = argparse.ArgumentParser() 186 187 # TODO(hidehiko): Support to specify the Chromium's revision number. 188 parser.add_argument( 189 '--chromium_root', 190 help='Root directory to the local chromium repository.') 191 parser.add_argument( 192 '--output_root', 193 default=_LIBCHROME_ROOT, 194 help='Output directory, which is libchrome root directory.') 195 parser.add_argument( 196 '--patch_dir', 197 default=os.path.join(_TOOLS_DIR, 'patch'), 198 help='Directory containing patch files to be applied.') 199 200 return parser.parse_args() 201 202 203def main(): 204 args = _parse_args() 205 _clean_existing_dir(args.output_root) 206 _import_files(args.chromium_root, args.output_root) 207 _apply_patch_files(args.patch_dir, args.output_root) 208 # TODO(hidehiko): Create a git commit with filling templated message. 209 210 211if __name__ == '__main__': 212 main() 213