Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # coding: utf-8 | |
| 3 | |
| 4 # Copyright 2015 The Chromium Authors. All rights reserved. | |
| 5 # Use of this source code is governed by a BSD-style license that can be | |
| 6 # found in the LICENSE file. | |
| 7 | |
| 8 import argparse | |
| 9 import os | |
| 10 import re | |
| 11 import subprocess | |
| 12 import sys | |
| 13 import textwrap | |
| 14 | |
| 15 | |
| 16 def main(args): | |
| 17 parser = argparse.ArgumentParser( | |
| 18 description='Update the in-tree copy of an imported project') | |
| 19 parser.add_argument( | |
| 20 '--project', | |
| 21 help='The imported project name, used for the git remote name', | |
| 22 metavar='PROJECT') | |
| 23 parser.add_argument( | |
| 24 '--repository', | |
| 25 default='https://chromium.googlesource.com/crashpad/crashpad', | |
| 26 help='The imported project\'s remote fetch URL', | |
| 27 metavar='URL') | |
| 28 parser.add_argument( | |
| 29 '--subtree', | |
| 30 default='third_party/crashpad/crashpad', | |
| 31 help='The imported project\'s location in this project\'s tree', | |
| 32 metavar='PATH') | |
| 33 parser.add_argument( | |
| 34 '--update-to', | |
| 35 help='What to update the imported project to', | |
| 36 metavar='COMMITISH') | |
| 37 parser.add_argument( | |
| 38 '--readme', | |
| 39 help='The README.chromium file describing the imported project', | |
| 40 metavar='FILE', | |
| 41 dest='readme_path') | |
| 42 parser.add_argument( | |
| 43 '--keep-remote', | |
| 44 default='default', | |
| 45 choices=['default', 'no', 'yes'], | |
| 46 help='Whether to keep the imported project\'s remote when done') | |
| 47 parsed = parser.parse_args(args) | |
| 48 | |
| 49 original_head = \ | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
I think our coding style is more in favor of paren
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
| |
| 50 subprocess.check_output(['git', 'rev-parse', 'HEAD']).rstrip() | |
| 51 | |
| 52 # Read the README, because that’s what it’s for. Extract a few things from | |
| 53 # it, and save it to be able to update it later. | |
| 54 readme_path = parsed.readme_path or \ | |
| 55 os.path.join(os.path.dirname(__file__ or '.'), 'README.chromium') | |
| 56 readme_content_old = open(readme_path).read() | |
| 57 | |
| 58 project_name_match = re.search( | |
| 59 r'^Name:\s+(.*)$', readme_content_old, re.MULTILINE) | |
| 60 project_name = project_name_match.group(1) | |
| 61 | |
| 62 project_shortname_match = re.search( | |
| 63 r'^Short Name:\s+(.*)$', readme_content_old, re.MULTILINE) | |
| 64 project_shortname = project_shortname_match.group(1) | |
| 65 | |
| 66 # Extract the original commit hash from the README. | |
| 67 revision_match = re.search(r'^Revision:\s+([0-9a-fA-F]{40})($|\s)', | |
| 68 readme_content_old, | |
| 69 re.MULTILINE) | |
| 70 revision_old = revision_match.group(1) | |
| 71 | |
| 72 project = parsed.project or project_shortname | |
| 73 | |
| 74 added_remote = False | |
| 75 try: | |
| 76 # The remote might already exist. Check for it first, and make sure the | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
you don't need to add the remote here.
I think wha
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
Primiano Tucci (use gerrit)
2015/12/10 15:26:13
git rev-parse FETCH_HEAD will always give you a sh
Mark Mentovai
2015/12/10 15:31:28
Sure, but if I say update.py --update-to=6789abcd,
Mark Mentovai
2015/12/10 15:50:01
I wrote:
Primiano Tucci (use gerrit)
2015/12/10 15:53:57
Ahh that's the part I was missing. I think the ans
| |
| 77 # URL matches what was specified. | |
| 78 remote_url = subprocess.check_output( | |
| 79 ['git', 'config', '--local', 'remote.' + project + '.url']).rstrip() | |
| 80 if remote_url != parsed.repository: | |
| 81 raise Exception( | |
| 82 'repository mismatch', parsed.repository, remote_url) | |
| 83 except subprocess.CalledProcessError as e: | |
| 84 if e.returncode == 1: | |
| 85 # The remote doesn’t exist. Add it. | |
| 86 subprocess.check_call( | |
| 87 ['git', 'remote', 'add', project, parsed.repository]) | |
| 88 added_remote = True | |
| 89 | |
| 90 subprocess.check_call(['git', 'fetch', project]) | |
| 91 | |
| 92 commitish_new = parsed.update_to or project + '/master' | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
and this would become FETCH_HEAD
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
| |
| 93 update_range = revision_old + '..' + commitish_new | |
| 94 | |
| 95 # This cherry-picks each change in the window from the upstream project into | |
| 96 # the current branch. | |
| 97 subprocess.check_call(['git', | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
Not necessary for this CL: I think you want to be
Mark Mentovai
2015/12/10 15:16:01
Primiano Tucci wrote:
Mark Mentovai
2015/12/10 20:08:50
Did this now.
| |
| 98 'cherry-pick', | |
| 99 '--keep-redundant', | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
Isn't this --keep-redundant-commits (with -commits
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
Primiano Tucci (use gerrit)
2015/12/10 15:26:13
ah ok. I never figured out how git really does pat
| |
| 100 '--strategy=subtree', | |
| 101 '-Xsubtree=' + parsed.subtree, | |
| 102 '-x', | |
| 103 update_range]) | |
| 104 | |
| 105 # Make a nice commit message. Start with the full commit hash. | |
| 106 revision_new = subprocess.check_output( | |
| 107 ['git', 'rev-parse', commitish_new]).rstrip() | |
| 108 new_message = 'Update ' + project_name + ' to ' + revision_new + '\n\n' | |
| 109 | |
| 110 # Get an abbreviated hash and subject line for each commit in the window, | |
| 111 # sorted in chronological order. Wrap everything to 72 characters, with a | |
| 112 # hanging indent. | |
| 113 log_lines = subprocess.check_output(['git', | |
| 114 '-c', | |
| 115 'core.abbrev=12', | |
| 116 'log', | |
| 117 '--abbrev-commit', | |
| 118 '--pretty=oneline', | |
| 119 '--reverse', | |
| 120 update_range]).splitlines(False) | |
| 121 wrapper = textwrap.TextWrapper(width=72, subsequent_indent = ' ' * 13) | |
| 122 for line in log_lines: | |
| 123 # Strip trailing periods from subjects. | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
such classy :)
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
| |
| 124 if line.endswith('.'): | |
| 125 line = line[:-1] | |
| 126 | |
| 127 # If any subjects have what look like commit hashes in them, truncate | |
| 128 # them to 12 characters. | |
| 129 line = re.sub(r'(\s)([0-9a-fA-F]{12})([0-9a-fA-F]{28})($|\s)', | |
|
Primiano Tucci (use gerrit)
2015/12/10 09:31:21
Hmm dunno about this. This would make copy / grepp
Mark Mentovai
2015/12/10 15:13:55
Primiano Tucci wrote:
| |
| 130 r'\1\2\4', | |
| 131 line) | |
| 132 | |
| 133 new_message += '\n'.join(wrapper.wrap(line)) + '\n' | |
| 134 | |
| 135 # Update the README with the new hash. | |
| 136 readme_content_new = re.sub( | |
| 137 r'^(Revision:\s+)([0-9a-fA-F]{40})($|\s.*?$)', | |
| 138 r'\g<1>' + revision_new, | |
| 139 readme_content_old, | |
| 140 1, | |
| 141 re.MULTILINE) | |
| 142 | |
| 143 # If the in-tree copy has no changes relative to the upstream, clear the | |
| 144 # “Local Modifications” section of the README. | |
| 145 has_local_modifications = True | |
| 146 try: | |
| 147 subprocess.check_call(['git', | |
| 148 'diff-tree', | |
| 149 '--quiet', | |
| 150 commitish_new, | |
| 151 'HEAD:' + parsed.subtree]) | |
| 152 has_local_modifications = False | |
| 153 readme_content_new = re.sub(r'\nLocal Modifications:\n.*$', | |
| 154 '\nLocal Modifications:\nNone.', | |
| 155 readme_content_new, | |
| 156 1) | |
| 157 except subprocess.CalledProcessError, e: | |
| 158 # If the return code is 1, swallow the exception. There are local | |
| 159 # modifications. | |
| 160 if e.returncode != 1: | |
| 161 raise | |
| 162 | |
| 163 # This soft-reset causes all of the cherry-picks to show up as staged, | |
| 164 # which will have the effect of squashing them along with the README update | |
| 165 # when committed below. | |
| 166 subprocess.check_call(['git', 'reset', '--soft', original_head]) | |
| 167 | |
| 168 # Remove the remote if desired. | |
| 169 if parsed.keep_remote == 'no' or \ | |
| 170 (parsed.keep_remote == 'default' and added_remote): | |
| 171 subprocess.check_call(['git', 'remote', 'remove', project]) | |
| 172 | |
| 173 # Write the new README. | |
| 174 open(readme_path, 'w').write(readme_content_new) | |
| 175 | |
| 176 # Commit everything. | |
| 177 subprocess.check_call(['git', 'add', readme_path]) | |
| 178 subprocess.check_call(['git', 'commit', '--message=' + new_message]) | |
| 179 | |
| 180 if has_local_modifications: | |
| 181 print 'Remember to check the Local Modifications section in ' + \ | |
| 182 readme_path | |
| 183 | |
| 184 return 0 | |
| 185 | |
| 186 | |
| 187 if __name__ == '__main__': | |
| 188 sys.exit(main(sys.argv[1:])) | |
| OLD | NEW |