roll.py 7.0 KB

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