xref: /aosp_15_r20/external/libchrome/libchrome_tools/update_libchrome.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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