Skip to content

Commit abc9f9a

Browse files
authored
[flutter_plugin_tools] If clang-format does not run, fall back to other executables in PATH (flutter#6853)
* If clang-format does not run, fall back to other executables in PATH * Review edits
1 parent fd2841f commit abc9f9a

File tree

6 files changed

+90
-13
lines changed

6 files changed

+90
-13
lines changed

script/tool/CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
## 13.1
1+
## 0.13.2
2+
3+
* Falls back to other executables in PATH when `clang-format` does not run.
4+
5+
## 0.13.1
26

37
* Updates `version-check` to recognize Pigeon's platform test structure.
48
* Pins `package:git` dependency to `2.0.x` until `dart >=2.18.0` becomes our

script/tool/lib/src/create_all_packages_app_command.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ class CreateAllPackagesAppCommand extends PackageCommand {
230230

231231
String _pubspecToString(Pubspec pubspec) {
232232
return '''
233-
### Generated file. Do not edit. Run `pub global run flutter_plugin_tools gen-pubspec` to update.
233+
### Generated file. Do not edit. Run `dart pub global run flutter_plugin_tools gen-pubspec` to update.
234234
name: ${pubspec.name}
235235
description: ${pubspec.description}
236236
publish_to: none

script/tool/lib/src/format_command.dart

+44-9
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ class FormatCommand extends PackageCommand {
104104
print('These files are not formatted correctly (see diff below):');
105105
LineSplitter.split(stdout).map((String line) => ' $line').forEach(print);
106106

107-
print('\nTo fix run "pub global activate flutter_plugin_tools && '
108-
'pub global run flutter_plugin_tools format" or copy-paste '
107+
print('\nTo fix run "dart pub global activate flutter_plugin_tools && '
108+
'dart pub global run flutter_plugin_tools format" or copy-paste '
109109
'this command into your terminal:');
110110

111111
final io.ProcessResult diff = await processRunner.run(
@@ -128,16 +128,11 @@ class FormatCommand extends PackageCommand {
128128
final Iterable<String> clangFiles = _getPathsWithExtensions(
129129
files, <String>{'.h', '.m', '.mm', '.cc', '.cpp'});
130130
if (clangFiles.isNotEmpty) {
131-
final String clangFormat = getStringArg('clang-format');
132-
if (!await _hasDependency(clangFormat)) {
133-
printError('Unable to run "clang-format". Make sure that it is in your '
134-
'path, or provide a full path with --clang-format.');
135-
throw ToolExit(_exitDependencyMissing);
136-
}
131+
final String clangFormat = await _findValidClangFormat();
137132

138133
print('Formatting .cc, .cpp, .h, .m, and .mm files...');
139134
final int exitCode = await _runBatched(
140-
getStringArg('clang-format'), <String>['-i', '--style=file'],
135+
clangFormat, <String>['-i', '--style=file'],
141136
files: clangFiles);
142137
if (exitCode != 0) {
143138
printError(
@@ -147,6 +142,26 @@ class FormatCommand extends PackageCommand {
147142
}
148143
}
149144

145+
Future<String> _findValidClangFormat() async {
146+
final String clangFormatArg = getStringArg('clang-format');
147+
if (await _hasDependency(clangFormatArg)) {
148+
return clangFormatArg;
149+
}
150+
151+
// There is a known issue where "chromium/depot_tools/clang-format"
152+
// fails with "Problem while looking for clang-format in Chromium source tree".
153+
// Loop through all "clang-format"s in PATH until a working one is found,
154+
// for example "/usr/local/bin/clang-format" or a "brew" installed version.
155+
for (final String clangFormatPath in await _whichAll('clang-format')) {
156+
if (await _hasDependency(clangFormatPath)) {
157+
return clangFormatPath;
158+
}
159+
}
160+
printError('Unable to run "clang-format". Make sure that it is in your '
161+
'path, or provide a full path with --clang-format.');
162+
throw ToolExit(_exitDependencyMissing);
163+
}
164+
150165
Future<void> _formatJava(
151166
Iterable<String> files, String googleFormatterPath) async {
152167
final Iterable<String> javaFiles =
@@ -279,6 +294,26 @@ class FormatCommand extends PackageCommand {
279294
return true;
280295
}
281296

297+
/// Returns all instances of [command] executable found on user path.
298+
Future<List<String>> _whichAll(String command) async {
299+
try {
300+
final io.ProcessResult result =
301+
await processRunner.run('which', <String>['-a', command]);
302+
303+
if (result.exitCode != 0) {
304+
return <String>[];
305+
}
306+
307+
final String stdout = result.stdout.trim() as String;
308+
if (stdout.isEmpty) {
309+
return <String>[];
310+
}
311+
return LineSplitter.split(stdout).toList();
312+
} on io.ProcessException {
313+
return <String>[];
314+
}
315+
}
316+
282317
/// Runs [command] on [arguments] on all of the files in [files], batched as
283318
/// necessary to avoid OS command-line length limits.
284319
///

script/tool/lib/src/main.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void main(List<String> args) {
5252
}
5353

5454
final CommandRunner<void> commandRunner = CommandRunner<void>(
55-
'pub global run flutter_plugin_tools',
55+
'dart pub global run flutter_plugin_tools',
5656
'Productivity utils for hosting multiple plugins within one repository.')
5757
..addCommand(AnalyzeCommand(packagesDir))
5858
..addCommand(BuildExamplesCommand(packagesDir))

script/tool/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: flutter_plugin_tools
22
description: Productivity utils for flutter/plugins and flutter/packages
33
repository: https://github.com/flutter/plugins/tree/main/script/tool
4-
version: 0.13.1
4+
version: 0.13.2
55

66
dependencies:
77
args: ^2.1.0

script/tool/test/format_command_test.dart

+38
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,44 @@ void main() {
332332
]));
333333
});
334334

335+
test('falls back to working clang-format in the path', () async {
336+
const List<String> files = <String>[
337+
'linux/foo_plugin.cc',
338+
'macos/Classes/Foo.h',
339+
];
340+
final RepositoryPackage plugin = createFakePlugin(
341+
'a_plugin',
342+
packagesDir,
343+
extraFiles: files,
344+
);
345+
346+
processRunner.mockProcessesForExecutable['clang-format'] = <io.Process>[
347+
MockProcess(exitCode: 1)
348+
];
349+
processRunner.mockProcessesForExecutable['which'] = <io.Process>[
350+
MockProcess(
351+
stdout: '/usr/local/bin/clang-format\n/path/to/working-clang-format')
352+
];
353+
processRunner.mockProcessesForExecutable['/usr/local/bin/clang-format'] =
354+
<io.Process>[MockProcess(exitCode: 1)];
355+
await runCapturingPrint(runner, <String>['format']);
356+
357+
expect(
358+
processRunner.recordedCalls,
359+
containsAll(<ProcessCall>[
360+
const ProcessCall(
361+
'/path/to/working-clang-format', <String>['--version'], null),
362+
ProcessCall(
363+
'/path/to/working-clang-format',
364+
<String>[
365+
'-i',
366+
'--style=file',
367+
...getPackagesDirRelativePaths(plugin, files)
368+
],
369+
packagesDir.path),
370+
]));
371+
});
372+
335373
test('honors --clang-format flag', () async {
336374
const List<String> files = <String>[
337375
'windows/foo_plugin.cpp',

0 commit comments

Comments
 (0)