Index: clang/tools/clang-format/git-clang-format =================================================================== --- clang/tools/clang-format/git-clang-format +++ clang/tools/clang-format/git-clang-format @@ -184,8 +184,12 @@ binary=opts.binary, style=opts.style) else: - old_tree = create_tree_from_workdir(changed_lines) + if opts.staged: + old_tree = create_tree_from_index(changed_lines) + else: + old_tree = create_tree_from_workdir(changed_lines) new_tree = run_clang_format_and_save_to_tree(changed_lines, + revision="" if opts.staged else None, binary=opts.binary, style=opts.style) if opts.verbose >= 1: @@ -393,12 +397,27 @@ Returns the object ID (SHA-1) of the created tree.""" 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 +425,14 @@ 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 +444,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 +471,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 +485,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