1
1
#!/usr/bin/env python3
2
2
#
3
- # ===- git-clang-format - ClangFormat Git Integration --------- *- python -*--===#
3
+ # ===- git-clang-format - ClangFormat Git Integration -------*- python -*--=== #
4
4
#
5
5
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6
6
# See https://llvm.org/LICENSE.txt for license information.
7
7
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8
8
#
9
- # ===------------------------------------------------------------------------ ===#
9
+ # ===----------------------------------------------------------------------=== #
10
10
11
11
r"""
12
12
clang-format git integration
@@ -32,7 +32,9 @@ import re
32
32
import subprocess
33
33
import sys
34
34
35
- usage = "git clang-format [OPTIONS] [<commit>] [<commit>|--staged] " "[--] [<file>...]"
35
+ usage = (
36
+ "git clang-format [OPTIONS] [<commit>] [<commit>|--staged] [--] [<file>...]"
37
+ )
36
38
37
39
desc = """
38
40
If zero or one commits are given, run clang-format on all lines that differ
@@ -161,13 +163,20 @@ def main():
161
163
),
162
164
),
163
165
p .add_argument (
164
- "-f" , "--force" , action = "store_true" , help = "allow changes to unstaged files"
166
+ "-f" ,
167
+ "--force" ,
168
+ action = "store_true" ,
169
+ help = "allow changes to unstaged files" ,
165
170
)
166
171
p .add_argument (
167
172
"-p" , "--patch" , action = "store_true" , help = "select hunks interactively"
168
173
)
169
174
p .add_argument (
170
- "-q" , "--quiet" , action = "count" , default = 0 , help = "print less information"
175
+ "-q" ,
176
+ "--quiet" ,
177
+ action = "count" ,
178
+ default = 0 ,
179
+ help = "print less information" ,
171
180
)
172
181
p .add_argument (
173
182
"--staged" ,
@@ -181,7 +190,11 @@ def main():
181
190
help = "passed to clang-format" ,
182
191
),
183
192
p .add_argument (
184
- "-v" , "--verbose" , action = "count" , default = 0 , help = "print extra information"
193
+ "-v" ,
194
+ "--verbose" ,
195
+ action = "count" ,
196
+ default = 0 ,
197
+ help = "print extra information" ,
185
198
)
186
199
p .add_argument (
187
200
"--diff_from_common_commit" ,
@@ -221,7 +234,10 @@ def main():
221
234
if not opts .diff :
222
235
die ("--diff is required when two commits are given" )
223
236
elif opts .diff_from_common_commit :
224
- die ("--diff_from_common_commit is only allowed when two commits are given" )
237
+ die (
238
+ "--diff_from_common_commit is only allowed when two commits are "
239
+ "given"
240
+ )
225
241
226
242
if os .path .dirname (opts .binary ):
227
243
opts .binary = os .path .abspath (opts .binary )
@@ -296,9 +312,9 @@ def main():
296
312
def load_git_config (non_string_options = None ):
297
313
"""Return the git configuration as a dictionary.
298
314
299
- All options are assumed to be strings unless in `non_string_options`, in which
300
- is a dictionary mapping option name (in lower case) to either "--bool" or
301
- "--int"."""
315
+ All options are assumed to be strings unless in `non_string_options`, in
316
+ which is a dictionary mapping option name (in lower case) to either "--bool"
317
+ or "--int"."""
302
318
if non_string_options is None :
303
319
non_string_options = {}
304
320
out = {}
@@ -323,9 +339,9 @@ def interpret_args(args, dash_dash, default_commit):
323
339
args and placed in `dash_dash`.
324
340
325
341
If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its
326
- left (if present) are taken as commits. Otherwise, the arguments are checked
327
- from left to right if they are commits or files. If commits are not given,
328
- a list with `default_commit` is used."""
342
+ left (if present) are taken as commits. Otherwise, the arguments are
343
+ checked from left to right if they are commits or files. If commits are not
344
+ given, a list with `default_commit` is used."""
329
345
if dash_dash :
330
346
if len (args ) == 0 :
331
347
commits = [default_commit ]
@@ -367,7 +383,10 @@ def disambiguate_revision(value):
367
383
return False
368
384
if object_type in ("commit" , "tag" ):
369
385
return True
370
- die ("`%s` is a %s, but a commit or filename was expected" % (value , object_type ))
386
+ die (
387
+ "`%s` is a %s, but a commit or filename was expected"
388
+ % (value , object_type )
389
+ )
371
390
372
391
373
392
def get_object_type (value ):
@@ -442,7 +461,9 @@ def extract_lines(patch_file):
442
461
line_count = 1
443
462
if start_line == 0 :
444
463
continue
445
- matches .setdefault (filename , []).append (Range (start_line , line_count ))
464
+ matches .setdefault (filename , []).append (
465
+ Range (start_line , line_count )
466
+ )
446
467
return matches
447
468
448
469
@@ -497,9 +518,19 @@ def create_tree_from_index(filenames):
497
518
498
519
def index_contents_generator ():
499
520
for filename in filenames :
500
- git_ls_files_cmd = ["git" , "ls-files" , "--stage" , "-z" , "--" , filename ]
521
+ git_ls_files_cmd = [
522
+ "git" ,
523
+ "ls-files" ,
524
+ "--stage" ,
525
+ "-z" ,
526
+ "--" ,
527
+ filename ,
528
+ ]
501
529
git_ls_files = subprocess .Popen (
502
- git_ls_files_cmd , env = env , stdin = subprocess .PIPE , stdout = subprocess .PIPE
530
+ git_ls_files_cmd ,
531
+ env = env ,
532
+ stdin = subprocess .PIPE ,
533
+ stdout = subprocess .PIPE ,
503
534
)
504
535
stdout = git_ls_files .communicate ()[0 ]
505
536
yield convert_string (stdout .split (b"\0 " )[0 ])
@@ -534,7 +565,13 @@ def run_clang_format_and_save_to_tree(
534
565
os .path .basename (filename ),
535
566
]
536
567
else :
537
- git_metadata_cmd = ["git" , "ls-files" , "--stage" , "--" , filename ]
568
+ git_metadata_cmd = [
569
+ "git" ,
570
+ "ls-files" ,
571
+ "--stage" ,
572
+ "--" ,
573
+ filename ,
574
+ ]
538
575
git_metadata = subprocess .Popen (
539
576
git_metadata_cmd ,
540
577
env = env ,
@@ -566,8 +603,8 @@ def create_tree(input_lines, mode):
566
603
567
604
If mode is '--stdin', it must be a list of filenames. If mode is
568
605
'--index-info' is must be a list of values suitable for "git update-index
569
- --index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other mode
570
- is invalid."""
606
+ --index-info", such as "<mode> <SP> <sha1> <TAB> <filename>". Any other
607
+ mode is invalid."""
571
608
assert mode in ("--stdin" , "--index-info" )
572
609
cmd = ["git" , "update-index" , "--add" , "-z" , mode ]
573
610
with temporary_index_file ():
@@ -582,13 +619,18 @@ def create_tree(input_lines, mode):
582
619
583
620
584
621
def clang_format_to_blob (
585
- filename , line_ranges , revision = None , binary = "clang-format" , style = None , env = None
622
+ filename ,
623
+ line_ranges ,
624
+ revision = None ,
625
+ binary = "clang-format" ,
626
+ style = None ,
627
+ env = None ,
586
628
):
587
629
"""Run clang-format on the given file and save the result to a git blob.
588
630
589
631
Runs on the file in `revision` if not None, or on the file in the working
590
- directory if `revision` is None. Revision can be set to an empty string to run
591
- clang-format on the file in the index.
632
+ directory if `revision` is None. Revision can be set to an empty string to
633
+ run clang-format on the file in the index.
592
634
593
635
Returns the object ID (SHA-1) of the created blob."""
594
636
clang_format_cmd = [binary ]
@@ -602,7 +644,12 @@ def clang_format_to_blob(
602
644
)
603
645
if revision is not None :
604
646
clang_format_cmd .extend (["--assume-filename=" + filename ])
605
- git_show_cmd = ["git" , "cat-file" , "blob" , "%s:%s" % (revision , filename )]
647
+ git_show_cmd = [
648
+ "git" ,
649
+ "cat-file" ,
650
+ "blob" ,
651
+ "%s:%s" % (revision , filename ),
652
+ ]
606
653
git_show = subprocess .Popen (
607
654
git_show_cmd , env = env , stdin = subprocess .PIPE , stdout = subprocess .PIPE
608
655
)
@@ -624,7 +671,13 @@ def clang_format_to_blob(
624
671
else :
625
672
raise
626
673
clang_format_stdin .close ()
627
- hash_object_cmd = ["git" , "hash-object" , "-w" , "--path=" + filename , "--stdin" ]
674
+ hash_object_cmd = [
675
+ "git" ,
676
+ "hash-object" ,
677
+ "-w" ,
678
+ "--path=" + filename ,
679
+ "--stdin" ,
680
+ ]
628
681
hash_object = subprocess .Popen (
629
682
hash_object_cmd , stdin = clang_format .stdout , stdout = subprocess .PIPE
630
683
)
@@ -641,8 +694,8 @@ def clang_format_to_blob(
641
694
642
695
@contextlib .contextmanager
643
696
def temporary_index_file (tree = None ):
644
- """Context manager for setting GIT_INDEX_FILE to a temporary file and deleting
645
- the file afterward."""
697
+ """Context manager for setting GIT_INDEX_FILE to a temporary file and
698
+ deleting the file afterward."""
646
699
index_path = create_temporary_index (tree )
647
700
old_index_path = os .environ .get ("GIT_INDEX_FILE" )
648
701
os .environ ["GIT_INDEX_FILE" ] = index_path
@@ -671,9 +724,9 @@ def create_temporary_index(tree=None):
671
724
672
725
def print_diff (old_tree , new_tree ):
673
726
"""Print the diff between the two trees to stdout."""
674
- # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
675
- # is expected to be viewed by the user, and only the former does nice things
676
- # like color and pagination.
727
+ # We use the porcelain 'diff' and not plumbing 'diff-tree' because the
728
+ # output is expected to be viewed by the user, and only the former does nice
729
+ # things like color and pagination.
677
730
#
678
731
# We also only print modified files since `new_tree` only contains the files
679
732
# that were modified, so unmodified files would show as deleted without the
@@ -685,15 +738,23 @@ def print_diff(old_tree, new_tree):
685
738
686
739
def print_diffstat (old_tree , new_tree ):
687
740
"""Print the diffstat between the two trees to stdout."""
688
- # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
689
- # is expected to be viewed by the user, and only the former does nice things
690
- # like color and pagination.
741
+ # We use the porcelain 'diff' and not plumbing 'diff-tree' because the
742
+ # output is expected to be viewed by the user, and only the former does nice
743
+ # things like color and pagination.
691
744
#
692
745
# We also only print modified files since `new_tree` only contains the files
693
746
# that were modified, so unmodified files would show as deleted without the
694
747
# filter.
695
748
return subprocess .run (
696
- ["git" , "diff" , "--diff-filter=M" , "--exit-code" , "--stat" , old_tree , new_tree ]
749
+ [
750
+ "git" ,
751
+ "diff" ,
752
+ "--diff-filter=M" ,
753
+ "--exit-code" ,
754
+ "--stat" ,
755
+ old_tree ,
756
+ new_tree ,
757
+ ]
697
758
).returncode
698
759
699
760
@@ -717,10 +778,13 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
717
778
.split ("\0 " )
718
779
)
719
780
if not force :
720
- unstaged_files = run ("git" , "diff-files" , "--name-status" , * changed_files )
781
+ unstaged_files = run (
782
+ "git" , "diff-files" , "--name-status" , * changed_files
783
+ )
721
784
if unstaged_files :
722
785
print (
723
- "The following files would be modified but " "have unstaged changes:" ,
786
+ "The following files would be modified but have unstaged "
787
+ "changes:" ,
724
788
file = sys .stderr ,
725
789
)
726
790
print (unstaged_files , file = sys .stderr )
@@ -749,7 +813,10 @@ def run(*args, **kwargs):
749
813
for name in kwargs :
750
814
raise TypeError ("run() got an unexpected keyword argument '%s'" % name )
751
815
p = subprocess .Popen (
752
- args , stdout = subprocess .PIPE , stderr = subprocess .PIPE , stdin = subprocess .PIPE
816
+ args ,
817
+ stdout = subprocess .PIPE ,
818
+ stderr = subprocess .PIPE ,
819
+ stdin = subprocess .PIPE ,
753
820
)
754
821
stdout , stderr = p .communicate (input = stdin )
755
822
@@ -759,13 +826,17 @@ def run(*args, **kwargs):
759
826
if p .returncode == 0 :
760
827
if stderr :
761
828
if verbose :
762
- print ("`%s` printed to stderr:" % " " .join (args ), file = sys .stderr )
829
+ print (
830
+ "`%s` printed to stderr:" % " " .join (args ), file = sys .stderr
831
+ )
763
832
print (stderr .rstrip (), file = sys .stderr )
764
833
if strip :
765
834
stdout = stdout .rstrip ("\r \n " )
766
835
return stdout
767
836
if verbose :
768
- print ("`%s` returned %s" % (" " .join (args ), p .returncode ), file = sys .stderr )
837
+ print (
838
+ "`%s` returned %s" % (" " .join (args ), p .returncode ), file = sys .stderr
839
+ )
769
840
if stderr :
770
841
print (stderr .rstrip (), file = sys .stderr )
771
842
sys .exit (2 )
0 commit comments