1#!/usr/bin/env python 2# Copyright 2019 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6from __future__ import print_function 7import argparse 8import sys 9import os 10import subprocess 11import glob 12import shutil 13 14 15FILES_TO_SYNC = [ 16 'README.md', 17 'check_protocol_compatibility.py', 18 'code_generator.py', 19 'concatenate_protocols.py', 20 'convert_protocol_to_json.py', 21 'encoding/encoding.h', 22 'encoding/encoding.cc', 23 'encoding/encoding_test.cc', 24 'inspector_protocol.gni', 25 'inspector_protocol.gypi', 26 'lib/*', 27 'pdl.py', 28 'templates/*', 29] 30 31 32def RunCmd(cmd): 33 p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 34 (stdoutdata, stderrdata) = p.communicate() 35 if p.returncode != 0: 36 raise Exception('%s: exit status %d', str(cmd), p.returncode) 37 return stdoutdata 38 39 40def CheckRepoIsClean(path, suffix): 41 os.chdir(path) # As a side effect this also checks for existence of the dir. 42 # If path isn't a git repo, this will throw and exception. 43 # And if it is a git repo and 'git status' has anything interesting to say, 44 # then it's not clean (uncommitted files etc.) 45 if len(RunCmd(['git', 'status', '--porcelain'])) != 0: 46 raise Exception('%s is not a clean git repo (run git status)' % path) 47 if not path.endswith(suffix): 48 raise Exception('%s does not end with /%s' % (path, suffix)) 49 50 51def CheckRepoIsNotAtMasterBranch(path): 52 os.chdir(path) 53 stdout = RunCmd(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip() 54 if stdout == 'master': 55 raise Exception('%s is at master branch - refusing to copy there.' % path) 56 57 58def CheckRepoIsV8Checkout(path): 59 os.chdir(path) 60 if (RunCmd(['git', 'config', '--get', 'remote.origin.url']).strip() != 61 'https://chromium.googlesource.com/v8/v8.git'): 62 raise Exception('%s is not a proper V8 checkout.' % path) 63 64 65def CheckRepoIsInspectorProtocolCheckout(path): 66 os.chdir(path) 67 if (RunCmd(['git', 'config', '--get', 'remote.origin.url']).strip() != 68 'https://chromium.googlesource.com/deps/inspector_protocol.git'): 69 raise Exception('%s is not a proper inspector_protocol checkout.' % path) 70 71 72def FindFilesToSyncIn(path): 73 files = [] 74 for f in FILES_TO_SYNC: 75 files += glob.glob(os.path.join(path, f)) 76 files = [os.path.relpath(f, path) for f in files] 77 return files 78 79 80def FilesAreEqual(path1, path2): 81 # We check for permissions (useful for executable scripts) and contents. 82 return (os.stat(path1).st_mode == os.stat(path2).st_mode and 83 open(path1).read() == open(path2).read()) 84 85 86def GetHeadRevision(path): 87 os.chdir(path) 88 return RunCmd(['git', 'rev-parse', 'HEAD']) 89 90 91def main(argv): 92 parser = argparse.ArgumentParser(description=( 93 "Rolls the inspector_protocol project (upstream) into V8's " 94 "third_party (downstream).")) 95 parser.add_argument("--ip_src_upstream", 96 help="The inspector_protocol (upstream) tree.", 97 default="~/ip/src") 98 parser.add_argument("--v8_src_downstream", 99 help="The V8 src tree.", 100 default="~/v8/v8") 101 parser.add_argument('--force', dest='force', action='store_true', 102 help=("Whether to carry out the modifications " 103 "in the destination tree.")) 104 parser.set_defaults(force=False) 105 106 args = parser.parse_args(argv) 107 upstream = os.path.normpath(os.path.expanduser(args.ip_src_upstream)) 108 downstream = os.path.normpath(os.path.expanduser( 109 args.v8_src_downstream)) 110 CheckRepoIsClean(upstream, '/src') 111 CheckRepoIsClean(downstream, '/v8') 112 CheckRepoIsInspectorProtocolCheckout(upstream) 113 CheckRepoIsV8Checkout(downstream) 114 # Check that the destination Git repo isn't at the master branch - it's 115 # generally a bad idea to check into the master branch, so we catch this 116 # common pilot error here early. 117 CheckRepoIsNotAtMasterBranch(downstream) 118 src_dir = upstream 119 dest_dir = os.path.join(downstream, 'third_party/inspector_protocol') 120 print('Rolling %s into %s ...' % (src_dir, dest_dir)) 121 src_files = set(FindFilesToSyncIn(src_dir)) 122 dest_files = set(FindFilesToSyncIn(dest_dir)) 123 to_add = [f for f in src_files if f not in dest_files] 124 to_delete = [f for f in dest_files if f not in src_files] 125 to_copy = [f for f in src_files 126 if (f in dest_files and not FilesAreEqual( 127 os.path.join(src_dir, f), os.path.join(dest_dir, f)))] 128 print('To add: %s' % to_add) 129 print('To delete: %s' % to_delete) 130 print('To copy: %s' % to_copy) 131 if not to_add and not to_delete and not to_copy: 132 print('Nothing to do. You\'re good.') 133 sys.exit(0) 134 if not args.force: 135 print('Rerun with --force if you wish the modifications to be done.') 136 sys.exit(1) 137 print('You said --force ... as you wish, modifying the destination.') 138 for f in to_add + to_copy: 139 contents = open(os.path.join(src_dir, f)).read() 140 contents = contents.replace( 141 'INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_', 142 'V8_INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_') 143 contents = contents.replace( 144 'namespace inspector_protocol_encoding', 145 'namespace v8_inspector_protocol_encoding') 146 open(os.path.join(dest_dir, f), 'w').write(contents) 147 shutil.copymode(os.path.join(src_dir, f), os.path.join(dest_dir, f)) 148 for f in to_delete: 149 os.unlink(os.path.join(dest_dir, f)) 150 head_revision = GetHeadRevision(upstream) 151 lines = open(os.path.join(dest_dir, 'README.v8')).readlines() 152 f = open(os.path.join(dest_dir, 'README.v8'), 'w') 153 for line in lines: 154 if line.startswith('Revision: '): 155 f.write('Revision: %s' % head_revision) 156 else: 157 f.write(line) 158 f.close() 159 160 161if __name__ == '__main__': 162 sys.exit(main(sys.argv[1:])) 163