@@ -45,21 +45,24 @@ enum MessageType {
45
45
46
46
enum FormatCheck {
47
47
clang,
48
+ gn,
48
49
java,
50
+ python,
49
51
whitespace,
50
- gn,
51
52
}
52
53
53
54
FormatCheck nameToFormatCheck (String name) {
54
55
switch (name) {
55
56
case 'clang' :
56
57
return FormatCheck .clang;
58
+ case 'gn' :
59
+ return FormatCheck .gn;
57
60
case 'java' :
58
61
return FormatCheck .java;
62
+ case 'python' :
63
+ return FormatCheck .python;
59
64
case 'whitespace' :
60
65
return FormatCheck .whitespace;
61
- case 'gn' :
62
- return FormatCheck .gn;
63
66
default :
64
67
throw FormattingException ('Unknown FormatCheck type $name ' );
65
68
}
@@ -69,12 +72,14 @@ String formatCheckToName(FormatCheck check) {
69
72
switch (check) {
70
73
case FormatCheck .clang:
71
74
return 'C++/ObjC' ;
75
+ case FormatCheck .gn:
76
+ return 'GN' ;
72
77
case FormatCheck .java:
73
78
return 'Java' ;
79
+ case FormatCheck .python:
80
+ return 'Python' ;
74
81
case FormatCheck .whitespace:
75
82
return 'Trailing whitespace' ;
76
- case FormatCheck .gn:
77
- return 'GN' ;
78
83
}
79
84
}
80
85
@@ -140,6 +145,15 @@ abstract class FormatChecker {
140
145
allFiles: allFiles,
141
146
messageCallback: messageCallback,
142
147
);
148
+ case FormatCheck .gn:
149
+ return GnFormatChecker (
150
+ processManager: processManager,
151
+ baseGitRef: baseGitRef,
152
+ repoDir: repoDir,
153
+ srcDir: srcDir,
154
+ allFiles: allFiles,
155
+ messageCallback: messageCallback,
156
+ );
143
157
case FormatCheck .java:
144
158
return JavaFormatChecker (
145
159
processManager: processManager,
@@ -149,17 +163,17 @@ abstract class FormatChecker {
149
163
allFiles: allFiles,
150
164
messageCallback: messageCallback,
151
165
);
152
- case FormatCheck .whitespace :
153
- return WhitespaceFormatChecker (
166
+ case FormatCheck .python :
167
+ return PythonFormatChecker (
154
168
processManager: processManager,
155
169
baseGitRef: baseGitRef,
156
170
repoDir: repoDir,
157
171
srcDir: srcDir,
158
172
allFiles: allFiles,
159
173
messageCallback: messageCallback,
160
174
);
161
- case FormatCheck .gn :
162
- return GnFormatChecker (
175
+ case FormatCheck .whitespace :
176
+ return WhitespaceFormatChecker (
163
177
processManager: processManager,
164
178
baseGitRef: baseGitRef,
165
179
repoDir: repoDir,
@@ -665,6 +679,93 @@ class GnFormatChecker extends FormatChecker {
665
679
}
666
680
}
667
681
682
+ /// Checks the format of any .py files using the "yapf" command.
683
+ class PythonFormatChecker extends FormatChecker {
684
+ PythonFormatChecker ({
685
+ ProcessManager processManager = const LocalProcessManager (),
686
+ required String baseGitRef,
687
+ required Directory repoDir,
688
+ required Directory srcDir,
689
+ bool allFiles = false ,
690
+ MessageCallback ? messageCallback,
691
+ }) : super (
692
+ processManager: processManager,
693
+ baseGitRef: baseGitRef,
694
+ repoDir: repoDir,
695
+ srcDir: srcDir,
696
+ allFiles: allFiles,
697
+ messageCallback: messageCallback,
698
+ ) {
699
+ yapfBin = File (path.join (
700
+ repoDir.absolute.path,
701
+ 'tools' ,
702
+ 'yapf.sh' ,
703
+ ));
704
+ _yapfStyle = File (path.join (
705
+ repoDir.absolute.path,
706
+ '.style.yapf' ,
707
+ ));
708
+ }
709
+
710
+ late final File yapfBin;
711
+ late final File _yapfStyle;
712
+
713
+ @override
714
+ Future <bool > checkFormatting () async {
715
+ message ('Checking Python formatting...' );
716
+ return (await _runYapfCheck (fixing: false )) == 0 ;
717
+ }
718
+
719
+ @override
720
+ Future <bool > fixFormatting () async {
721
+ message ('Fixing Python formatting...' );
722
+ await _runYapfCheck (fixing: true );
723
+ // The yapf script shouldn't fail when fixing errors.
724
+ return true ;
725
+ }
726
+
727
+ Future <int > _runYapfCheck ({required bool fixing}) async {
728
+ final List <String > filesToCheck = await getFileList (< String > ['*.py' ]);
729
+
730
+ final List <String > cmd = < String > [
731
+ yapfBin.path,
732
+ '--style' , _yapfStyle.path,
733
+ if (! fixing) '--diff' ,
734
+ if (fixing) '--in-place' ,
735
+ ];
736
+ final List <WorkerJob > jobs = < WorkerJob > [];
737
+ for (final String file in filesToCheck) {
738
+ jobs.add (WorkerJob (< String > [...cmd, file]));
739
+ }
740
+ final ProcessPool yapfPool = ProcessPool (
741
+ processRunner: _processRunner,
742
+ printReport: namedReport ('python format' ),
743
+ );
744
+ final List <WorkerJob > completedJobs = await yapfPool.runToCompletion (jobs);
745
+ reportDone ();
746
+ final List <String > incorrect = < String > [];
747
+ for (final WorkerJob job in completedJobs) {
748
+ if (job.result.exitCode == 1 ) {
749
+ incorrect.add (' ${job .command .last }\n ${job .result .output }' );
750
+ }
751
+ }
752
+ if (incorrect.isNotEmpty) {
753
+ final bool plural = incorrect.length > 1 ;
754
+ if (fixing) {
755
+ message ('Fixed ${incorrect .length } python file${plural ? 's' : '' }'
756
+ ' which ${plural ? 'were' : 'was' } formatted incorrectly.' );
757
+ } else {
758
+ error ('Found ${incorrect .length } python file${plural ? 's' : '' }'
759
+ ' which ${plural ? 'were' : 'was' } formatted incorrectly:' );
760
+ incorrect.forEach (stderr.writeln);
761
+ }
762
+ } else {
763
+ message ('All python files formatted correctly.' );
764
+ }
765
+ return incorrect.length;
766
+ }
767
+ }
768
+
668
769
@immutable
669
770
class _GrepResult {
670
771
const _GrepResult (this .file, [this .hits = const < String > [], this .lineNumbers = const < int > []]);
0 commit comments