diff --git a/clang/tools/clang-format/git-clang-format b/clang/tools/clang-format/git-clang-format --- a/clang/tools/clang-format/git-clang-format +++ b/clang/tools/clang-format/git-clang-format @@ -179,15 +179,17 @@ if len(commits) > 1: old_tree = commits[1] - new_tree = run_clang_format_and_save_to_tree(changed_lines, - revision=commits[1], - binary=opts.binary, - style=opts.style) + revision = old_tree + elif opts.staged: + old_tree = create_tree_from_index(changed_lines) + revision = '' else: old_tree = create_tree_from_workdir(changed_lines) - new_tree = run_clang_format_and_save_to_tree(changed_lines, - binary=opts.binary, - style=opts.style) + revision = None + new_tree = run_clang_format_and_save_to_tree(changed_lines, + revision, + binary=opts.binary, + style=opts.style) if opts.verbose >= 1: print('old tree: %s' % old_tree) print('new tree: %s' % new_tree) @@ -394,11 +396,29 @@ return create_tree(filenames, '--stdin') +def create_tree_from_index(filenames): + # Copy the environment, because the files have to be read from the original + # index. + env = os.environ.copy() + def index_contents_generator(): + for filename in filenames: + git_ls_files_cmd = ['git', 'ls-files', '--stage', '-z', '--', filename] + git_ls_files = subprocess.Popen(git_ls_files_cmd, env=env, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout = git_ls_files.communicate()[0] + yield convert_string(stdout.split(b'\0')[0]) + return create_tree(index_contents_generator(), '--index-info') + + def run_clang_format_and_save_to_tree(changed_lines, revision=None, binary='clang-format', style=None): """Run clang-format on each file and save the result to a git tree. Returns the object ID (SHA-1) of the created tree.""" + # Copy the environment when formatting the files in the index, because the + # files have to be read from the original index. + env = os.environ.copy() if revision == '' else None def iteritems(container): try: return container.iteritems() # Python 2 @@ -406,11 +426,15 @@ return container.items() # Python 3 def index_info_generator(): for filename, line_ranges in iteritems(changed_lines): - if revision: - git_metadata_cmd = ['git', 'ls-tree', - '%s:%s' % (revision, os.path.dirname(filename)), - os.path.basename(filename)] - git_metadata = subprocess.Popen(git_metadata_cmd, stdin=subprocess.PIPE, + if revision is not None: + if len(revision) > 0: + git_metadata_cmd = ['git', 'ls-tree', + '%s:%s' % (revision, os.path.dirname(filename)), + os.path.basename(filename)] + else: + git_metadata_cmd = ['git', 'ls-files', '--stage', '--', filename] + git_metadata = subprocess.Popen(git_metadata_cmd, env=env, + stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout = git_metadata.communicate()[0] mode = oct(int(stdout.split()[0], 8)) @@ -422,7 +446,8 @@ blob_id = clang_format_to_blob(filename, line_ranges, revision=revision, binary=binary, - style=style) + style=style, + env=env) yield '%s %s\t%s' % (mode, blob_id, filename) return create_tree(index_info_generator(), '--index-info') @@ -448,11 +473,12 @@ def clang_format_to_blob(filename, line_ranges, revision=None, - binary='clang-format', style=None): + binary='clang-format', style=None, env=None): """Run clang-format on the given file and save the result to a git blob. Runs on the file in `revision` if not None, or on the file in the working - directory if `revision` is None. + directory if `revision` is None. Revision can be set to an empty string to run + clang-format on the file in the index. Returns the object ID (SHA-1) of the created blob.""" clang_format_cmd = [binary] @@ -461,10 +487,10 @@ clang_format_cmd.extend([ '-lines=%s:%s' % (start_line, start_line+line_count-1) for start_line, line_count in line_ranges]) - if revision: + if revision is not None: clang_format_cmd.extend(['-assume-filename='+filename]) git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)] - git_show = subprocess.Popen(git_show_cmd, stdin=subprocess.PIPE, + git_show = subprocess.Popen(git_show_cmd, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE) git_show.stdin.close() clang_format_stdin = git_show.stdout