Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 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 os.path | |
| 10 import shutil | |
| 11 import subprocess | |
| 12 import sys | |
| 13 import tempfile | |
| 14 | |
| 15 # How to patch libxml2 in Chromium: | |
| 16 # | |
| 17 # 1. Write a .patch file and add it to third_party/libxml/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 libxml2 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/libxml2 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 libxml2 repo directory: | |
| 44 # a. git remote update origin | |
| 45 # b. git checkout origin/master | |
| 46 # | |
| 47 # This will be the upstream version of libxml you are rolling to. | |
| 48 # | |
| 49 # 2. On Linux, in the Chromium src director: | |
| 50 # a. third_party/libxml/chromium/roll.py --linux /path/to/libxml2 | |
| 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_libxml | |
| 57 # | |
| 58 # 2. On Windows, in the Chromium src directory: | |
| 59 # a. git fetch wip refs/wip/$USER/roll_libxml | |
| 60 # b. git checkout FETCH_HEAD | |
| 61 # c. third_party\libxml\chromium\roll.py --win32 | |
| 62 # d. git push -f wip HEAD:refs/wip/$USER/roll_libxml | |
| 63 # | |
| 64 # 3. On Mac, in the Chromium src directory: | |
| 65 # a. git fetch wip refs/wip/$USER/roll_libxml | |
| 66 # b. git checkout -b roll_libxml_nnnn FETCH_HEAD | |
| 67 # c. git branch --set-upstream-to origin/master | |
| 68 # d. third_party/libxml/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 = [ | |
|
Oliver Chang
2017/04/06 01:09:24
nit: maybe rename these global constants to upperc
| |
| 74 'chromium-issue-599427.patch', | |
| 75 'chromium-issue-620679.patch', | |
| 76 'chromium-issue-628581.patch', | |
| 77 'chromium-issue-683629.patch', | |
| 78 ] | |
| 79 | |
| 80 | |
| 81 # These two sets of options should be in sync. You can check the | |
| 82 # generated #defines in (win32|mac|linux)/include/libxml.h to confirm | |
| 83 # this. | |
| 84 | |
| 85 # See libxml2 configure.ac to learn what options are available. | |
| 86 xml_configure_options = [ | |
| 87 '--with-icu', | |
| 88 '--without-c14n', | |
| 89 '--without-catalog', | |
| 90 '--without-debug', | |
| 91 '--without-docbook', | |
| 92 '--without-ftp', | |
| 93 '--without-http', | |
| 94 '--without-iconv', | |
| 95 '--without-legacy', | |
| 96 '--without-lzma', | |
| 97 '--without-mem-debug', | |
| 98 '--without-modules', | |
| 99 '--without-readline', | |
| 100 '--without-regexps', | |
| 101 '--without-run-debug', | |
| 102 '--without-schemas', | |
| 103 '--without-schematron', | |
| 104 '--without-valid', | |
| 105 '--without-xinclude', | |
| 106 '--without-xptr', | |
| 107 '--without-zlib', | |
| 108 '--without-history', | |
| 109 ] | |
| 110 | |
| 111 | |
| 112 # See libxml2 win32/configure.js to learn what options are available. | |
| 113 xml_win32_configure_options = [ | |
|
Oliver Chang
2017/04/06 01:09:24
it seems a little difficult to me to make sure tha
| |
| 114 'icu=yes', | |
| 115 | |
|
Oliver Chang
2017/04/06 01:09:24
nit: extra newline?
| |
| 116 'c14n=no', | |
| 117 'catalog=no', | |
| 118 'docb=no', | |
| 119 'ftp=no', | |
| 120 'http=no', | |
| 121 'iconv=no', | |
| 122 'legacy=no', | |
| 123 'lzma=no', | |
| 124 'mem_debug=no', | |
| 125 'modules=no', | |
| 126 'regexps=no', | |
| 127 'run_debug=no', | |
| 128 'schemas=no', | |
| 129 'schematron=no', | |
| 130 'valid=no', | |
| 131 'walker=no', | |
| 132 'xinclude=no', | |
| 133 'xml_debug=no', | |
| 134 'xptr=no', | |
| 135 'zlib=no', | |
| 136 ] | |
| 137 | |
| 138 | |
| 139 third_party_libxml_src = 'third_party/libxml/src' | |
| 140 | |
| 141 | |
| 142 class WorkingDir(object): | |
| 143 """"Changes the working directory and resets it on exit.""" | |
| 144 def __init__(self, path): | |
| 145 self.prev_path = os.getcwd() | |
| 146 self.path = path | |
| 147 | |
| 148 def __enter__(self): | |
| 149 os.chdir(self.path) | |
| 150 | |
| 151 def __exit__(self, exc_type, exc_value, traceback): | |
| 152 if exc_value: | |
| 153 print('was in %s; %s before that' % (self.path, self.prev_path)) | |
| 154 os.chdir(self.prev_path) | |
| 155 | |
| 156 | |
| 157 def git(*args): | |
| 158 """Runs a git subcommand. | |
| 159 | |
| 160 On Windows this uses the shell because there's a git wrapper | |
| 161 batch file in depot_tools. | |
| 162 | |
| 163 Arguments: | |
| 164 args: The arguments to pass to git. | |
| 165 """ | |
| 166 command = ['git'] + list(args) | |
| 167 subprocess.check_call(command, shell=(os.name == 'nt')) | |
| 168 | |
| 169 | |
| 170 def remove_tracked_and_local_dir(path): | |
| 171 """Removes the contents of a directory from git, and the filesystem. | |
| 172 | |
| 173 Arguments: | |
| 174 path: The path to remove. | |
| 175 """ | |
| 176 remove_tracked_files([path]) | |
| 177 shutil.rmtree(path, ignore_errors=True) | |
| 178 os.mkdir(path) | |
| 179 | |
| 180 | |
| 181 def remove_tracked_files(files_to_remove): | |
| 182 """Removes tracked files from git. | |
| 183 | |
| 184 Arguments: | |
| 185 files_to_remove: The files to remove. | |
| 186 """ | |
| 187 files_to_remove = [f for f in files_to_remove if os.path.exists(f)] | |
| 188 git('rm', '-rf', *files_to_remove) | |
| 189 | |
| 190 | |
| 191 def sed_in_place(input_filename, program): | |
| 192 """Replaces text in a file. | |
| 193 | |
| 194 Arguments: | |
| 195 input_filename: The file to edit. | |
| 196 program: The sed program to perform edits on the file. | |
| 197 """ | |
| 198 # OS X's sed requires -e | |
| 199 subprocess.check_call(['sed', '-i', '-e', program, input_filename]) | |
| 200 | |
| 201 | |
| 202 def check_copying(full_path_to_third_party_libxml_src): | |
| 203 path = os.path.join(full_path_to_third_party_libxml_src, 'COPYING') | |
| 204 if not os.path.exists(path): | |
| 205 return | |
| 206 with open(path) as f: | |
| 207 s = f.read() | |
| 208 if 'GNU' in s: | |
| 209 raise Exception('check COPYING') | |
| 210 | |
| 211 | |
| 212 def prepare_libxml_distribution(libxml2_repo_path, temp_dir): | |
| 213 """Makes a libxml2 distribution. | |
| 214 | |
| 215 Args: | |
| 216 libxml2_repo_path: The path to the local clone of the libxml2 repo. | |
| 217 temp_dir: A temporary directory to stage the distribution to. | |
| 218 | |
| 219 Returns: A tuple of commit hash and full path to the archive. | |
| 220 """ | |
| 221 # If it was necessary to push from a distribution prepared upstream, | |
| 222 # this is the point to inject it: Return the version string and the | |
| 223 # distribution tar file. | |
| 224 | |
| 225 # The libxml2 repo we're pulling changes from should not have | |
| 226 # local changes. This *should* be a commit that's publicly visible | |
| 227 # in the upstream repo; reviewers should check this. | |
| 228 check_clean(libxml2_repo_path) | |
| 229 | |
| 230 temp_config_path = os.path.join(temp_dir, 'config') | |
| 231 os.mkdir(temp_config_path) | |
| 232 temp_src_path = os.path.join(temp_dir, 'src') | |
| 233 os.mkdir(temp_src_path) | |
| 234 | |
| 235 with WorkingDir(libxml2_repo_path): | |
| 236 commit = subprocess.check_output( | |
| 237 ['git', 'log', '-n', '1', '--pretty=format:%H', 'HEAD']) | |
| 238 subprocess.check_call( | |
| 239 'git archive HEAD | tar -x -C "%s"' % temp_src_path, | |
| 240 shell=True) | |
| 241 with WorkingDir(temp_src_path): | |
| 242 os.remove('.gitignore') | |
| 243 with WorkingDir(temp_config_path): | |
| 244 subprocess.check_call(['../src/autogen.sh'] + xml_configure_options) | |
| 245 subprocess.check_call(['make', 'dist-all']) | |
| 246 | |
| 247 # Work out what it is called | |
| 248 tar_file = subprocess.check_output( | |
| 249 '''awk '/PACKAGE =/ {p=$3} /VERSION =/ {v=$3} ''' | |
| 250 '''END {printf("%s-%s.tar.gz", p, v)}' Makefile''', | |
| 251 shell=True) | |
| 252 return commit, os.path.abspath(tar_file) | |
| 253 | |
| 254 | |
| 255 def roll_libxml_linux(src_path, libxml2_repo_path): | |
| 256 with WorkingDir(src_path): | |
| 257 # Export the upstream git repo. | |
| 258 try: | |
| 259 temp_dir = tempfile.mkdtemp() | |
| 260 print('temporary directory: %s' % temp_dir) | |
| 261 | |
| 262 commit, tar_file = prepare_libxml_distribution(libxml2_repo_path, | |
| 263 temp_dir) | |
| 264 | |
| 265 # Remove all of the old libxml to ensure only desired cruft | |
| 266 # accumulates | |
| 267 remove_tracked_and_local_dir(third_party_libxml_src) | |
| 268 | |
| 269 # Update the libxml repo and export it to the Chromium tree | |
| 270 with WorkingDir(third_party_libxml_src): | |
| 271 subprocess.check_call( | |
| 272 'tar xzf %s --strip-components=1' % tar_file, | |
| 273 shell=True) | |
| 274 finally: | |
| 275 shutil.rmtree(temp_dir) | |
| 276 | |
| 277 with WorkingDir(third_party_libxml_src): | |
| 278 # Put the version number is the README file | |
| 279 sed_in_place('../README.chromium', | |
| 280 's/Version: .*$/Version: %s/' % commit) | |
| 281 | |
| 282 for patch in patches: | |
| 283 subprocess.check_call('cat ../chromium/%s | patch -p1' % patch, | |
| 284 shell=True) | |
| 285 | |
| 286 with WorkingDir('../linux'): | |
| 287 subprocess.check_call( | |
| 288 ['../src/autogen.sh'] + xml_configure_options) | |
| 289 check_copying(os.getcwd()) | |
| 290 sed_in_place('config.h', 's/#define HAVE_RAND_R 1//') | |
| 291 | |
| 292 # Add *everything* | |
| 293 with WorkingDir('../src'): | |
| 294 git('add', '*') | |
| 295 git('commit', '-am', '%s libxml, linux' % commit) | |
| 296 print('Now push to Windows and run steps there.') | |
| 297 | |
| 298 | |
| 299 def roll_libxml_win32(src_path): | |
| 300 with WorkingDir(src_path): | |
| 301 # Run the configure script. | |
| 302 with WorkingDir(os.path.join(third_party_libxml_src, 'win32')): | |
| 303 subprocess.check_call( | |
| 304 ['cscript', '//E:jscript', 'configure.js', 'compiler=msvc'] + | |
| 305 xml_win32_configure_options) | |
| 306 | |
| 307 # Add and commit the result. | |
| 308 shutil.move('VC10/config.h', '../../win32/config.h') | |
| 309 git('add', '../../win32/config.h') | |
| 310 shutil.move('../include/libxml/xmlversion.h', | |
| 311 '../../win32/include/libxml/xmlversion.h') | |
| 312 git('add', '../../win32/include/libxml/xmlversion.h') | |
| 313 git('commit', '-m', 'Windows') | |
| 314 git('clean', '-f') | |
| 315 print('Now push to Mac and run steps there.') | |
| 316 | |
| 317 | |
| 318 def roll_libxml_mac(src_path): | |
| 319 full_path_to_third_party_libxml = os.path.join( | |
| 320 src_path, third_party_libxml_src, '..') | |
| 321 | |
| 322 with WorkingDir(os.path.join(full_path_to_third_party_libxml, 'mac')): | |
| 323 subprocess.check_call(['autoreconf', '-i', '../src']) | |
| 324 subprocess.check_call(['../src/configure'] + xml_configure_options) | |
| 325 sed_in_place('config.h', 's/#define HAVE_RAND_R 1//') | |
| 326 | |
| 327 with WorkingDir(full_path_to_third_party_libxml): | |
| 328 commit = subprocess.check_output(['awk', '/Version:/ {print $2}', | |
| 329 'README.chromium']) | |
| 330 files_to_remove = [ | |
|
Oliver Chang
2017/04/06 01:09:24
nit: maybe put this at the top with all the other
| |
| 331 'src/DOCBparser.c', | |
| 332 'src/HACKING', | |
| 333 'src/INSTALL.libxml2', | |
| 334 'src/MAINTAINERS', | |
| 335 'src/Makefile.win', | |
| 336 'src/README.cvs-commits', | |
| 337 # This is unneeded "legacy" SAX API, even though we enable SAX1. | |
| 338 'src/SAX.c', | |
| 339 'src/VxWorks', | |
| 340 'src/autogen.sh', | |
| 341 'src/autom4te.cache', | |
| 342 'src/bakefile', | |
| 343 'src/build_glob.py', | |
| 344 'src/c14n.c', | |
| 345 'src/catalog.c', | |
| 346 'src/chvalid.def', | |
| 347 'src/debugXML.c', | |
| 348 'src/doc', | |
| 349 'src/example', | |
| 350 'src/genChRanges.py', | |
| 351 'src/global.data', | |
| 352 'src/include/libxml/xmlversion.h', | |
| 353 'src/include/libxml/xmlwin32version.h', | |
| 354 'src/include/libxml/xmlwin32version.h.in', | |
| 355 'src/legacy.c', | |
| 356 'src/libxml2.doap', | |
| 357 'src/macos/libxml2.mcp.xml.sit.hqx', | |
| 358 'src/optim', | |
| 359 'src/os400', | |
| 360 'src/python', | |
| 361 'src/relaxng.c', | |
| 362 'src/result', | |
| 363 'src/rngparser.c', | |
| 364 'src/schematron.c', | |
| 365 'src/test', | |
| 366 'src/testOOM.c', | |
| 367 'src/testOOMlib.c', | |
| 368 'src/testOOMlib.h', | |
| 369 'src/trio.c', | |
| 370 'src/trio.h', | |
| 371 'src/triop.h', | |
| 372 'src/triostr.c', | |
| 373 'src/triostr.h', | |
| 374 'src/vms', | |
| 375 'src/win32/VC10/config.h', | |
| 376 'src/win32/wince', | |
| 377 'src/xinclude.c', | |
| 378 'src/xlink.c', | |
| 379 'src/xml2-config.in', | |
| 380 'src/xmlcatalog.c', | |
| 381 'src/xmllint.c', | |
| 382 'src/xmlmodule.c', | |
| 383 'src/xmlregexp.c', | |
| 384 'src/xmlschemas.c', | |
| 385 'src/xmlschemastypes.c', | |
| 386 'src/xpointer.c', | |
| 387 'src/xstc', | |
| 388 'src/xzlib.c', | |
| 389 ] | |
| 390 remove_tracked_files(files_to_remove) | |
| 391 commit_message = 'Roll libxml to %s' % commit | |
| 392 git('commit', '-am', commit_message) | |
| 393 print('Now upload for review, etc.') | |
| 394 | |
| 395 | |
| 396 def check_clean(path): | |
| 397 with WorkingDir(path): | |
| 398 status = subprocess.check_output(['git', 'status', '-s']) | |
| 399 if len(status) > 0: | |
| 400 raise Exception('repository at %s is not clean' % path) | |
| 401 | |
| 402 | |
| 403 def main(): | |
| 404 src_dir = os.getcwd() | |
| 405 if not os.path.exists(os.path.join(src_dir, 'third_party')): | |
| 406 print('error: run this script from the Chromium src directory') | |
| 407 sys.exit(1) | |
| 408 | |
| 409 parser = argparse.ArgumentParser( | |
| 410 description='Roll the libxml2 dependency in Chromium') | |
| 411 platform = parser.add_mutually_exclusive_group(required=True) | |
| 412 platform.add_argument('--linux', action='store_true') | |
| 413 platform.add_argument('--win32', action='store_true') | |
| 414 platform.add_argument('--mac', action='store_true') | |
| 415 parser.add_argument( | |
| 416 'libxml2_repo_path', | |
| 417 type=str, | |
| 418 nargs='?', | |
| 419 help='The path to the local clone of the libxml2 git repo.') | |
| 420 args = parser.parse_args() | |
| 421 | |
| 422 if args.linux: | |
| 423 libxml2_repo_path = args.libxml2_repo_path | |
| 424 if not libxml2_repo_path: | |
| 425 print('Specify the path to the local libxml2 repo clone.') | |
| 426 sys.exit(1) | |
| 427 libxml2_repo_path = os.path.abspath(libxml2_repo_path) | |
| 428 roll_libxml_linux(src_dir, libxml2_repo_path) | |
| 429 elif args.win32: | |
| 430 roll_libxml_win32(src_dir) | |
| 431 elif args.mac: | |
| 432 roll_libxml_mac(src_dir) | |
| 433 | |
| 434 | |
| 435 if __name__ == '__main__': | |
| 436 main() | |
| OLD | NEW |