Skip to content

Commit 94d13ae

Browse files
[tools] Format Dart per-package (flutter#8043)
Instead of running Dart formatting on the whole repo at once, run it per package, from the package's directory. This is slower, but necessary since the new formatter behaves differently depending on the package's min SDK version.
1 parent 72356fd commit 94d13ae

2 files changed

Lines changed: 57 additions & 52 deletions

File tree

script/tool/lib/src/format_command.dart

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import 'package:meta/meta.dart';
1111

1212
import 'common/core.dart';
1313
import 'common/output_utils.dart';
14-
import 'common/package_command.dart';
14+
import 'common/package_looping_command.dart';
15+
import 'common/repository_package.dart';
1516

1617
/// In theory this should be 8191, but in practice that was still resulting in
1718
/// "The input line is too long" errors. This was chosen as a value that worked
@@ -40,7 +41,7 @@ final Uri _kotlinFormatterUrl = Uri.https('maven.org',
4041
'/maven2/com/facebook/ktfmt/0.46/ktfmt-0.46-jar-with-dependencies.jar');
4142

4243
/// A command to format all package code.
43-
class FormatCommand extends PackageCommand {
44+
class FormatCommand extends PackageLoopingCommand {
4445
/// Creates an instance of the format command.
4546
FormatCommand(
4647
super.packagesDir, {
@@ -85,18 +86,19 @@ class FormatCommand extends PackageCommand {
8586
'to be in your path.';
8687

8788
@override
88-
Future<void> run() async {
89+
Future<void> initializeRun() async {
8990
final String javaFormatterPath = await _getJavaFormatterPath();
9091
final String kotlinFormatterPath = await _getKotlinFormatterPath();
9192

92-
// This class is not based on PackageLoopingCommand because running the
93-
// formatters separately for each package is an order of magnitude slower,
94-
// due to the startup overhead of the formatters.
93+
// All but Dart is formatted here rather than in runForPackage because
94+
// running the formatters separately for each package is an order of
95+
// magnitude slower, due to the startup overhead of the formatters.
96+
//
97+
// Dart has to be run per-package because the formatter can have different
98+
// behavior based on the package's SDK, which can't be determined if the
99+
// formatter isn't running in the context of the package.
95100
final Iterable<String> files =
96101
await _getFilteredFilePaths(getFiles(), relativeTo: packagesDir);
97-
if (getBoolArg(_dartArg)) {
98-
await _formatDart(files);
99-
}
100102
if (getBoolArg(_javaArg)) {
101103
await _formatJava(files, javaFormatterPath);
102104
}
@@ -109,7 +111,28 @@ class FormatCommand extends PackageCommand {
109111
if (getBoolArg(_swiftArg)) {
110112
await _formatAndLintSwift(files);
111113
}
114+
}
115+
116+
@override
117+
Future<PackageResult> runForPackage(RepositoryPackage package) async {
118+
final Iterable<String> files = await _getFilteredFilePaths(
119+
getFilesForPackage(package),
120+
relativeTo: package.directory,
121+
);
122+
if (getBoolArg(_dartArg)) {
123+
await _formatDart(files, workingDir: package.directory);
124+
}
125+
// Success or failure is determined overall in completeRun, since most code
126+
// isn't being validated per-package, so just always return success at the
127+
// package level.
128+
// TODO(stuartmorgan): Consider doing _didModifyAnything checks per-package
129+
// instead, since the other languages are already formatted by the time
130+
// this code is being run.
131+
return PackageResult.success();
132+
}
112133

134+
@override
135+
Future<void> completeRun() async {
113136
if (getBoolArg(_failonChangeArg)) {
114137
final bool modified = await _didModifyAnything();
115138
if (modified) {
@@ -291,13 +314,16 @@ class FormatCommand extends PackageCommand {
291314
}
292315
}
293316

294-
Future<void> _formatDart(Iterable<String> files) async {
317+
Future<void> _formatDart(
318+
Iterable<String> files, {
319+
Directory? workingDir,
320+
}) async {
295321
final Iterable<String> dartFiles =
296322
_getPathsWithExtensions(files, <String>{'.dart'});
297323
if (dartFiles.isNotEmpty) {
298324
print('Formatting .dart files...');
299-
final int exitCode =
300-
await _runBatched('dart', <String>['format'], files: dartFiles);
325+
final int exitCode = await _runBatched('dart', <String>['format'],
326+
files: dartFiles, workingDir: workingDir);
301327
if (exitCode != 0) {
302328
printError('Failed to format Dart files: exit code $exitCode.');
303329
throw ToolExit(_exitFlutterFormatFailed);
@@ -440,11 +466,8 @@ class FormatCommand extends PackageCommand {
440466
///
441467
/// Returns the exit code of the first failure, which stops the run, or 0
442468
/// on success.
443-
Future<int> _runBatched(
444-
String command,
445-
List<String> arguments, {
446-
required Iterable<String> files,
447-
}) async {
469+
Future<int> _runBatched(String command, List<String> arguments,
470+
{required Iterable<String> files, Directory? workingDir}) async {
448471
final int commandLineMax =
449472
platform.isWindows ? windowsCommandLineMax : nonWindowsCommandLineMax;
450473

@@ -462,7 +485,7 @@ class FormatCommand extends PackageCommand {
462485
batch.sort(); // For ease of testing.
463486
final int exitCode = await processRunner.runAndStream(
464487
command, <String>[...arguments, ...batch],
465-
workingDir: packagesDir);
488+
workingDir: workingDir ?? packagesDir);
466489
if (exitCode != 0) {
467490
return exitCode;
468491
}

script/tool/test/format_command_test.dart

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,13 @@ void main() {
6363
}
6464

6565
/// Returns a list of [count] relative paths to pass to [createFakePlugin]
66-
/// or [createFakePackage] with name [packageName] such that each path will
67-
/// be 99 characters long relative to [packagesDir].
66+
/// or [createFakePackage] such that each path will be 99 characters long
67+
/// relative to the package directory.
6868
///
6969
/// This is for each of testing batching, since it means each file will
7070
/// consume 100 characters of the batch length.
71-
List<String> get99CharacterPathExtraFiles(String packageName, int count) {
72-
final int padding = 99 -
73-
packageName.length -
74-
1 - // the path separator after the package name
71+
List<String> get99CharacterPathExtraFiles(int count) {
72+
const int padding = 99 -
7573
1 - // the path separator after the padding
7674
10; // the file name
7775
const int filenameBase = 10000;
@@ -100,10 +98,7 @@ void main() {
10098
expect(
10199
processRunner.recordedCalls,
102100
orderedEquals(<ProcessCall>[
103-
ProcessCall(
104-
'dart',
105-
<String>['format', ...getPackagesDirRelativePaths(plugin, files)],
106-
packagesDir.path),
101+
ProcessCall('dart', const <String>['format', ...files], plugin.path),
107102
]));
108103
});
109104

@@ -135,12 +130,7 @@ void main() {
135130
processRunner.recordedCalls,
136131
orderedEquals(<ProcessCall>[
137132
ProcessCall(
138-
'dart',
139-
<String>[
140-
'format',
141-
...getPackagesDirRelativePaths(plugin, formattedFiles)
142-
],
143-
packagesDir.path),
133+
'dart', const <String>['format', ...formattedFiles], plugin.path),
144134
]));
145135
});
146136

@@ -719,12 +709,7 @@ void main() {
719709
],
720710
packagesDir.path),
721711
ProcessCall(
722-
'dart',
723-
<String>[
724-
'format',
725-
...getPackagesDirRelativePaths(plugin, dartFiles)
726-
],
727-
packagesDir.path),
712+
'dart', const <String>['format', ...dartFiles], plugin.path),
728713
ProcessCall(
729714
'java',
730715
<String>[
@@ -899,11 +884,10 @@ void main() {
899884
const int batchSize = (windowsCommandLineMax ~/ 100) - 1;
900885

901886
// Make the file list one file longer than would fit in the batch.
902-
final List<String> batch1 =
903-
get99CharacterPathExtraFiles(pluginName, batchSize + 1);
887+
final List<String> batch1 = get99CharacterPathExtraFiles(batchSize + 1);
904888
final String extraFile = batch1.removeLast();
905889

906-
createFakePlugin(
890+
final RepositoryPackage package = createFakePlugin(
907891
pluginName,
908892
packagesDir,
909893
extraFiles: <String>[...batch1, extraFile],
@@ -921,9 +905,9 @@ void main() {
921905
'dart',
922906
<String>[
923907
'format',
924-
'$pluginName\\$extraFile',
908+
extraFile,
925909
],
926-
packagesDir.path),
910+
package.path),
927911
));
928912
});
929913

@@ -936,8 +920,7 @@ void main() {
936920
const int batchSize = (windowsCommandLineMax ~/ 100) - 1;
937921

938922
// Make the file list one file longer than would fit in a Windows batch.
939-
final List<String> batch =
940-
get99CharacterPathExtraFiles(pluginName, batchSize + 1);
923+
final List<String> batch = get99CharacterPathExtraFiles(batchSize + 1);
941924

942925
createFakePlugin(
943926
pluginName,
@@ -956,11 +939,10 @@ void main() {
956939
const int batchSize = (nonWindowsCommandLineMax ~/ 100) - 1;
957940

958941
// Make the file list one file longer than would fit in the batch.
959-
final List<String> batch1 =
960-
get99CharacterPathExtraFiles(pluginName, batchSize + 1);
942+
final List<String> batch1 = get99CharacterPathExtraFiles(batchSize + 1);
961943
final String extraFile = batch1.removeLast();
962944

963-
createFakePlugin(
945+
final RepositoryPackage package = createFakePlugin(
964946
pluginName,
965947
packagesDir,
966948
extraFiles: <String>[...batch1, extraFile],
@@ -978,9 +960,9 @@ void main() {
978960
'dart',
979961
<String>[
980962
'format',
981-
'$pluginName/$extraFile',
963+
extraFile,
982964
],
983-
packagesDir.path),
965+
package.path),
984966
));
985967
});
986968
}

0 commit comments

Comments
 (0)