Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
|
hayato
2017/05/09 06:31:45
Is this a new file written from scratch?
If we hav
| |
| 2 | |
| 3 # Copyright 2017 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 import argparse | |
| 8 import os | |
| 9 import shutil | |
| 10 import stat | |
| 11 import subprocess | |
| 12 import sys | |
| 13 import tempfile | |
| 14 | |
| 15 # How to patch libxslt in Chromium: | |
| 16 # | |
| 17 # 1. Write a .patch file and add it to third_party/libxslt/chromium. | |
| 18 # 2. Apply the patch in src: patch -p1 <../chromium/foo.patch | |
| 19 # 3. Add the patch to the list of patches in this file. | |
| 20 # 4. Update README.chromium with the provenance of the patch. | |
| 21 # 5. Upload a change with the modified documentation, roll script, | |
| 22 # patch, applied patch and any other relevant changes like | |
| 23 # regression tests. Go through the usual review and commit process. | |
| 24 # | |
| 25 # How to roll libxslt in Chromium: | |
| 26 # | |
| 27 # Prerequisites: | |
| 28 # | |
| 29 # 1. Check out Chromium somewhere on Linux, Mac and Windows. | |
| 30 # 2. On each machine, add the experimental remote named 'wip': | |
| 31 # git remote add -f wip \ | |
| 32 # https://chromium.googlesource.com/experimental/chromium/src | |
| 33 # 3. On Linux: | |
| 34 # a. sudo apt-get install libicu-dev | |
| 35 # b. git clone git://git.gnome.org/libxslt somewhere | |
| 36 # 4. On Mac, install these MacPorts: | |
| 37 # autoconf automake libtool pkgconfig icu | |
| 38 # | |
| 39 # Procedure: | |
| 40 # | |
| 41 # Warning: This process is destructive. Run it on a clean branch. | |
| 42 # | |
| 43 # 1. On Linux, in the libxslt repo directory: | |
| 44 # a. git remote update origin | |
| 45 # b. git checkout origin/master | |
| 46 # | |
| 47 # This will be the upstream version of libxslt you are rolling to. | |
| 48 # | |
| 49 # 2. On Linux, in the Chromium src director: | |
| 50 # a. third_party/libxslt/chromium/roll.py --linux /path/to/libxslt | |
| 51 # | |
| 52 # If this fails, it may be a patch no longer applies. Reset to | |
| 53 # head; modify the patch files, this script, and | |
| 54 # README.chromium; then commit the result and run it again. | |
| 55 # | |
| 56 # b. git push -f wip HEAD:refs/wip/$USER/roll_libxslt | |
| 57 # | |
| 58 # 2. On Windows, in the Chromium src directory: | |
| 59 # a. git fetch wip refs/wip/$USER/roll_libxslt | |
| 60 # b. git checkout FETCH_HEAD | |
| 61 # c. third_party\libxslt\chromium\roll.py --win32 | |
| 62 # d. git push -f wip HEAD:refs/wip/$USER/roll_libxslt | |
| 63 # | |
| 64 # 3. On Mac, in the Chromium src directory: | |
| 65 # a. git fetch wip refs/wip/$USER/roll_libxslt | |
| 66 # b. git checkout -b roll_libxslt_nnnn FETCH_HEAD | |
| 67 # c. git branch --set-upstream-to origin/master | |
| 68 # d. third_party/libxslt/chromium/roll.py --mac | |
| 69 # e. Make and commit any final changes to README.chromium, BUILD.gn, etc. | |
| 70 # f. Complete the code review process as usual: git cl upload -d; | |
| 71 # git cl try-results; etc. | |
| 72 | |
| 73 PATCHES = [ | |
| 74 'get-file-attributes-a.patch', | |
| 75 ] | |
| 76 | |
| 77 | |
| 78 # See libxslt configure.ac and win32/configure.js to learn what | |
| 79 # options are available. | |
| 80 | |
| 81 # These two sets of options should be in sync. You can check the | |
| 82 # generated #defines in (win32|mac|linux)/config.h to confirm | |
| 83 # this. | |
| 84 SHARED_XSLT_CONFIGURE_OPTIONS = [ | |
| 85 # These options are turned OFF | |
| 86 ('--without-debug', 'xslt_debug=no'), | |
| 87 ('--without-debugger', 'debugger=no'), | |
| 88 ('--without-mem-debug', 'mem_debug=no'), | |
| 89 ('--without-plugins', 'modules=no'), | |
| 90 ] | |
| 91 | |
| 92 # These options are only available in configure.ac for Linux and Mac. | |
| 93 EXTRA_NIX_XSLT_CONFIGURE_OPTIONS = [ | |
| 94 ] | |
| 95 | |
| 96 | |
| 97 # These options are only available in win32/configure.js for Windows. | |
| 98 EXTRA_WIN32_XSLT_CONFIGURE_OPTIONS = [ | |
| 99 'compiler=msvc', | |
| 100 'iconv=no', | |
| 101 ] | |
| 102 | |
| 103 | |
| 104 XSLT_CONFIGURE_OPTIONS = ( | |
| 105 [option[0] for option in SHARED_XSLT_CONFIGURE_OPTIONS] + | |
| 106 EXTRA_NIX_XSLT_CONFIGURE_OPTIONS) | |
| 107 | |
| 108 | |
| 109 XSLT_WIN32_CONFIGURE_OPTIONS = ( | |
| 110 [option[1] for option in SHARED_XSLT_CONFIGURE_OPTIONS] + | |
| 111 EXTRA_WIN32_XSLT_CONFIGURE_OPTIONS) | |
| 112 | |
| 113 | |
| 114 FILES_TO_REMOVE = [ | |
| 115 # TODO: Excluding ChangeLog and NEWS because encoding problems mean | |
| 116 # bots can't patch these. Reinclude them when there is a consistent | |
| 117 # encoding. | |
| 118 'src/NEWS', | |
| 119 'src/ChangeLog', | |
| 120 # These have shebang but not executable bit; presubmit will barf on them. | |
| 121 'src/autogen.sh', | |
| 122 'src/ltmain.sh', | |
| 123 'src/xslt-config.in', | |
| 124 # These are not needed. | |
| 125 'src/doc', | |
| 126 'src/python', | |
| 127 'src/tests', | |
| 128 'src/xsltproc', | |
| 129 'src/examples', | |
| 130 'src/vms', | |
| 131 ] | |
| 132 | |
| 133 | |
| 134 THIRD_PARTY_LIBXML_LINUX = 'third_party/libxml/linux' | |
| 135 THIRD_PARTY_LIBXSLT = 'third_party/libxslt' | |
| 136 THIRD_PARTY_LIBXSLT_SRC = os.path.join(THIRD_PARTY_LIBXSLT, 'src') | |
| 137 | |
| 138 | |
| 139 def libxml_path_option(src_path): | |
| 140 '''Gets the path to libxml/linux in Chromium. | |
| 141 | |
| 142 libxslt needs to be configured with libxml source. | |
| 143 | |
| 144 Args: | |
| 145 src_path: The Chromium src path. | |
| 146 | |
| 147 Returns: | |
| 148 The path to the libxml2 third_party/libxml/linux configure | |
| 149 output. | |
| 150 ''' | |
| 151 libxml_linux_path = os.path.join(src_path, THIRD_PARTY_LIBXML_LINUX) | |
| 152 return ['--with-libxml-src=%s' % libxml_linux_path] | |
| 153 | |
| 154 | |
| 155 class WorkingDir(object): | |
| 156 """"Changes the working directory and resets it on exit.""" | |
|
hayato
2017/05/09 06:52:46
Nit: """, instead of """".
| |
| 157 def __init__(self, path): | |
| 158 self.prev_path = os.getcwd() | |
| 159 self.path = path | |
| 160 | |
| 161 def __enter__(self): | |
| 162 os.chdir(self.path) | |
| 163 | |
| 164 def __exit__(self, exc_type, exc_value, traceback): | |
| 165 if exc_value: | |
| 166 print('was in %s; %s before that' % (self.path, self.prev_path)) | |
| 167 os.chdir(self.prev_path) | |
| 168 | |
| 169 | |
| 170 def git(*args): | |
| 171 """Runs a git subcommand. | |
| 172 | |
| 173 On Windows this uses the shell because there's a git wrapper | |
| 174 batch file in depot_tools. | |
| 175 | |
| 176 Arguments: | |
| 177 args: The arguments to pass to git. | |
| 178 """ | |
| 179 command = ['git'] + list(args) | |
| 180 subprocess.check_call(command, shell=(os.name == 'nt')) | |
| 181 | |
| 182 | |
| 183 def remove_tracked_and_local_dir(path): | |
| 184 """Removes the contents of a directory from git, and the filesystem. | |
| 185 | |
| 186 Arguments: | |
| 187 path: The path to remove. | |
| 188 """ | |
| 189 remove_tracked_files([path]) | |
| 190 shutil.rmtree(path, ignore_errors=True) | |
| 191 os.mkdir(path) | |
| 192 | |
| 193 | |
| 194 def remove_tracked_files(files_to_remove): | |
| 195 """Removes tracked files from git. | |
| 196 | |
| 197 Arguments: | |
| 198 files_to_remove: The files to remove. | |
| 199 """ | |
| 200 files_to_remove = [f for f in files_to_remove if os.path.exists(f)] | |
| 201 git('rm', '-rf', *files_to_remove) | |
| 202 | |
| 203 | |
| 204 def sed_in_place(input_filename, program): | |
| 205 """Replaces text in a file. | |
| 206 | |
| 207 Arguments: | |
| 208 input_filename: The file to edit. | |
| 209 program: The sed program to perform edits on the file. | |
| 210 """ | |
| 211 # OS X's sed requires -e | |
| 212 subprocess.check_call(['sed', '-i', '-e', program, input_filename]) | |
| 213 | |
| 214 | |
| 215 def check_copying(path='.'): | |
| 216 path = os.path.join(path, 'COPYING') | |
| 217 if not os.path.exists(path): | |
| 218 return | |
| 219 with open(path) as f: | |
| 220 s = f.read() | |
| 221 if 'GNU' in s: | |
| 222 raise Exception('check COPYING') | |
| 223 | |
| 224 | |
| 225 def patch_config(): | |
| 226 '''Changes autoconf results which can not be changed with options.''' | |
| 227 sed_in_place('config.h', 's/#define HAVE_CLOCK_GETTIME 1//') | |
| 228 | |
| 229 # https://crbug.com/670720 | |
| 230 sed_in_place('config.h', 's/#define HAVE_ASCTIME 1//') | |
| 231 sed_in_place('config.h', 's/#define HAVE_LOCALTIME 1//') | |
| 232 sed_in_place('config.h', 's/#define HAVE_MKTIME 1//') | |
| 233 | |
| 234 sed_in_place('config.log', | |
| 235 's/[a-z.0-9]\+\.corp\.google\.com/REDACTED/') | |
| 236 | |
| 237 | |
| 238 def prepare_libxslt_distribution(src_path, libxslt_repo_path, temp_dir): | |
| 239 """Makes a libxslt distribution. | |
| 240 | |
| 241 Args: | |
| 242 src_path: The Chromium repository src path, for finding libxslt. | |
| 243 libxslt_repo_path: The path to the local clone of the libxslt repo. | |
| 244 temp_dir: A temporary directory to stage the distribution to. | |
| 245 | |
| 246 Returns: A tuple of commit hash and full path to the archive. | |
| 247 """ | |
| 248 # If it was necessary to push from a distribution prepared upstream, | |
| 249 # this is the point to inject it: Return the version string and the | |
| 250 # distribution tar file. | |
| 251 | |
| 252 # The libxslt repo we're pulling changes from should not have | |
| 253 # local changes. This *should* be a commit that's publicly visible | |
| 254 # in the upstream repo; reviewers should check this. | |
| 255 check_clean(libxslt_repo_path) | |
| 256 | |
| 257 temp_config_path = os.path.join(temp_dir, 'config') | |
| 258 os.mkdir(temp_config_path) | |
| 259 temp_src_path = os.path.join(temp_dir, 'src') | |
| 260 os.mkdir(temp_src_path) | |
| 261 | |
| 262 with WorkingDir(libxslt_repo_path): | |
| 263 commit = subprocess.check_output( | |
| 264 ['git', 'log', '-n', '1', '--pretty=format:%H', 'HEAD']) | |
| 265 subprocess.check_call( | |
| 266 'git archive HEAD | tar -x -C "%s"' % temp_src_path, | |
| 267 shell=True) | |
| 268 with WorkingDir(temp_src_path): | |
| 269 os.remove('.gitignore') | |
| 270 with WorkingDir(temp_config_path): | |
| 271 subprocess.check_call(['../src/autogen.sh'] + XSLT_CONFIGURE_OPTIONS + | |
| 272 libxml_path_option(src_path)) | |
| 273 subprocess.check_call(['make', 'dist-all']) | |
| 274 | |
| 275 # Work out what it is called | |
| 276 tar_file = subprocess.check_output( | |
| 277 '''awk '/PACKAGE =/ {p=$3} /VERSION =/ {v=$3} ''' | |
| 278 '''END {printf("%s-%s.tar.gz", p, v)}' Makefile''', | |
| 279 shell=True) | |
| 280 return commit, os.path.abspath(tar_file) | |
| 281 | |
| 282 | |
| 283 def roll_libxslt_linux(src_path, repo_path): | |
| 284 check_clean(src_path) | |
| 285 with WorkingDir(src_path): | |
| 286 try: | |
| 287 temp_dir = tempfile.mkdtemp() | |
| 288 print('temporary directory is: %s' % temp_dir) | |
| 289 commit, tar_file = prepare_libxslt_distribution( | |
| 290 src_path, repo_path, temp_dir) | |
| 291 | |
| 292 # Remove all of the old libxslt to ensure only desired | |
| 293 # cruft accumulates | |
| 294 remove_tracked_and_local_dir(THIRD_PARTY_LIBXSLT_SRC) | |
| 295 | |
| 296 # Export the libxslt distribution to the Chromium tree | |
| 297 with WorkingDir(THIRD_PARTY_LIBXSLT_SRC): | |
| 298 subprocess.check_call( | |
| 299 'tar xzf %s --strip-components=1' % tar_file, | |
| 300 shell=True) | |
| 301 finally: | |
| 302 shutil.rmtree(temp_dir) | |
| 303 | |
| 304 with WorkingDir(THIRD_PARTY_LIBXSLT_SRC): | |
| 305 # Write the commit ID into the README.chromium file | |
| 306 sed_in_place('../README.chromium', | |
| 307 's/Version: .*$/Version: %s/' % commit) | |
| 308 check_copying() | |
| 309 | |
| 310 for patch in PATCHES: | |
| 311 subprocess.check_call( | |
| 312 'cat ../chromium/%s | patch -p1 --fuzz=0' % patch, | |
| 313 shell=True) | |
| 314 | |
| 315 with WorkingDir('../linux'): | |
| 316 subprocess.check_call(['../src/configure'] + | |
| 317 XSLT_CONFIGURE_OPTIONS + | |
| 318 libxml_path_option(src_path)) | |
| 319 check_copying() | |
| 320 patch_config() | |
| 321 # Other platforms share this, even though it is | |
| 322 # generated on Linux. Android and Windows do not have | |
| 323 # xlocale. | |
| 324 sed_in_place('libxslt/xsltconfig.h', | |
| 325 '/Locale support/,/#if 1/s/#if 1/#if 0/') | |
| 326 shutil.move('libxslt/xsltconfig.h', '../src/libxslt') | |
| 327 | |
| 328 git('add', '*') | |
| 329 git('commit', '-am', '%s libxslt, linux' % commit) | |
| 330 | |
| 331 print('Now push to Windows and runs steps there.') | |
| 332 | |
| 333 | |
| 334 def roll_libxslt_win32(src_path): | |
| 335 full_path_to_libxslt = os.path.join(src_path, THIRD_PARTY_LIBXSLT) | |
| 336 with WorkingDir(full_path_to_libxslt): | |
| 337 with WorkingDir('src/win32'): | |
| 338 # Run the configure script. | |
| 339 subprocess.check_call(['cscript', '//E:jscript', 'configure.js'] + | |
| 340 XSLT_WIN32_CONFIGURE_OPTIONS) | |
| 341 shutil.copy('src/config.h', 'win32/config.h') | |
| 342 git('add', 'win32/config.h') | |
| 343 git('commit', '--allow-empty', '-m', 'Windows') | |
| 344 print('Now push to Mac and run steps there.') | |
| 345 | |
| 346 | |
| 347 def roll_libxslt_mac(src_path): | |
| 348 full_path_to_libxslt = os.path.join(src_path, THIRD_PARTY_LIBXSLT) | |
| 349 with WorkingDir(full_path_to_libxslt): | |
| 350 with WorkingDir('mac'): | |
| 351 subprocess.check_call(['autoreconf', '-i', '../src']) | |
| 352 os.chmod('../src/configure', | |
| 353 os.stat('../src/configure').st_mode | stat.S_IXUSR) | |
| 354 # /linux in the configure options is not a typo; configure | |
| 355 # looks here to find xml2-config | |
| 356 subprocess.check_call(['../src/configure'] + | |
| 357 XSLT_CONFIGURE_OPTIONS) | |
| 358 check_copying() | |
| 359 patch_config() | |
| 360 # Commit and upload the result | |
| 361 git('add', 'config.h') | |
| 362 remove_tracked_files(FILES_TO_REMOVE) | |
| 363 git('commit', '-m', 'Mac') | |
| 364 print('Now upload for review, etc.') | |
| 365 | |
| 366 | |
| 367 def check_clean(path): | |
| 368 with WorkingDir(path): | |
| 369 status = subprocess.check_output(['git', 'status', '-s']) | |
| 370 if len(status) > 0: | |
| 371 raise Exception('repository at %s is not clean' % path) | |
| 372 | |
| 373 | |
| 374 def main(): | |
| 375 src_dir = os.getcwd() | |
| 376 if not os.path.exists(os.path.join(src_dir, 'third_party')): | |
| 377 print('error: run this script from the Chromium src directory') | |
| 378 sys.exit(1) | |
| 379 | |
| 380 parser = argparse.ArgumentParser( | |
| 381 description='Roll the libxslt dependency in Chromium') | |
| 382 platform = parser.add_mutually_exclusive_group(required=True) | |
| 383 platform.add_argument('--linux', action='store_true') | |
| 384 platform.add_argument('--win32', action='store_true') | |
| 385 platform.add_argument('--mac', action='store_true') | |
| 386 parser.add_argument( | |
| 387 'libxslt_repo_path', | |
| 388 type=str, | |
| 389 nargs='?', | |
| 390 help='The path to the local clone of the libxslt git repo.') | |
| 391 args = parser.parse_args() | |
| 392 | |
| 393 if args.linux: | |
| 394 libxslt_repo_path = args.libxslt_repo_path | |
| 395 if not libxslt_repo_path: | |
| 396 print('Specify the path to the local libxslt repo clone.') | |
| 397 sys.exit(1) | |
| 398 libxslt_repo_path = os.path.abspath(libxslt_repo_path) | |
| 399 roll_libxslt_linux(src_dir, libxslt_repo_path) | |
| 400 elif args.win32: | |
| 401 roll_libxslt_win32(src_dir) | |
| 402 elif args.mac: | |
| 403 roll_libxslt_mac(src_dir) | |
| 404 | |
| 405 | |
| 406 if __name__ == '__main__': | |
| 407 main() | |
| OLD | NEW |