diff --git a/engine/src/flutter/testing/skia_gold_client/test/skia_gold_client_test.dart b/engine/src/flutter/testing/skia_gold_client/test/skia_gold_client_test.dart index 3361fe954d7..af2221a484f 100644 --- a/engine/src/flutter/testing/skia_gold_client/test/skia_gold_client_test.dart +++ b/engine/src/flutter/testing/skia_gold_client/test/skia_gold_client_test.dart @@ -52,7 +52,7 @@ void main() { Map? dimensions, String? prefix, bool verbose = false, - io.ProcessResult Function(List command) onRun = _runUnhandled, + io.ProcessResult Function(FakeCommandLogEntry entry) onRun = _runUnhandled, }) { return SkiaGoldClient.forTesting( fixture.workDirectory, @@ -97,8 +97,8 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: {...presubmitEnv, 'GIT_BRANCH': 'merge-queue-foo'}, - onRun: (List command) { - expect(command, [ + onRun: (FakeCommandLogEntry entry) { + expect(entry.command, [ 'python tools/goldctl.py', 'auth', '--work-dir', @@ -132,8 +132,8 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: {...presubmitEnv, 'GIT_BRANCH': 'merge-queue-foo'}, - onRun: (List command) { - expect(command, [ + onRun: (FakeCommandLogEntry entry) { + expect(entry.command, [ 'python tools/goldctl.py', 'auth', '--work-dir', @@ -165,8 +165,8 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - expect(command, [ + onRun: (FakeCommandLogEntry entry) { + expect(entry.command, [ 'python tools/goldctl.py', 'auth', '--work-dir', @@ -190,9 +190,9 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { + onRun: (FakeCommandLogEntry entry) { callsToGoldctl++; - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'auth', '--work-dir', @@ -219,8 +219,8 @@ void main() { fixture, environment: presubmitEnv, verbose: true, - onRun: (List command) { - expect(command, [ + onRun: (FakeCommandLogEntry entry) { + expect(entry.command, [ 'python tools/goldctl.py', 'auth', '--verbose', @@ -246,7 +246,7 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { + onRun: (FakeCommandLogEntry entry) { return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text'); }, ); @@ -270,14 +270,14 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -315,14 +315,14 @@ void main() { fixture, environment: presubmitEnv, prefix: 'engine.', - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -363,14 +363,14 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -409,14 +409,14 @@ void main() { fixture, environment: presubmitEnv, verbose: true, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -458,14 +458,14 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -507,11 +507,11 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text'); @@ -541,14 +541,14 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: postsubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -587,14 +587,14 @@ void main() { fixture, environment: postsubmitEnv, verbose: true, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } - expect(command, [ + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'add', @@ -636,11 +636,11 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: postsubmitEnv, - onRun: (List command) { - if (command case ['git', ...]) { + onRun: (FakeCommandLogEntry entry) { + if (entry.command case ['git', ...]) { return io.ProcessResult(0, 0, mockCommitHash, ''); } - if (command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { + if (entry.command case ['python tools/goldctl.py', 'imgtest', 'init', ...]) { return io.ProcessResult(0, 0, '', ''); } return io.ProcessResult(1, 0, 'stdout-text', 'stderr-text'); @@ -670,8 +670,8 @@ void main() { final SkiaGoldClient client = createClient( fixture, environment: presubmitEnv, - onRun: (List command) { - expect(command, [ + onRun: (FakeCommandLogEntry entry) { + expect(entry.command, [ 'python tools/goldctl.py', 'imgtest', 'get', @@ -728,8 +728,8 @@ final class _TestFixture { } } -io.ProcessResult _runUnhandled(List command) { - throw UnimplementedError('Unhandled run: ${command.join(' ')}'); +io.ProcessResult _runUnhandled(FakeCommandLogEntry entry) { + throw UnimplementedError('Unhandled run: ${entry.command.join(' ')}'); } /// An in-memory fake of [io.HttpClient] that allows [getUrl] to be mocked. diff --git a/engine/src/flutter/tools/clang_tidy/test/clang_tidy_test.dart b/engine/src/flutter/tools/clang_tidy/test/clang_tidy_test.dart index 46d37ab4306..fd117039bc5 100644 --- a/engine/src/flutter/tools/clang_tidy/test/clang_tidy_test.dart +++ b/engine/src/flutter/tools/clang_tidy/test/clang_tidy_test.dart @@ -340,12 +340,12 @@ void main() { lintTarget: const LintChanged(), ), processManager: FakeProcessManager( - onStart: (List command) { - if (command.first == 'git') { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.first == 'git') { // This just allows git to not actually be called. return FakeProcess(); } - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -360,12 +360,12 @@ void main() { lintTarget: const LintRegex(r'.*test.*\.cc$'), ), processManager: FakeProcessManager( - onStart: (List command) { - if (command.first == 'git') { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.first == 'git') { // This just allows git to not actually be called. return FakeProcess(); } - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -377,12 +377,12 @@ void main() { final Fixture fixture = Fixture.fromOptions( Options(buildCommandsPath: io.File(buildCommands), lintTarget: const LintAll()), processManager: FakeProcessManager( - onStart: (List command) { - if (command.first == 'git') { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.first == 'git') { // This just allows git to not actually be called. return FakeProcess(); } - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -622,11 +622,11 @@ void main() { final String firstFilePath = (await fileListFixture.tool.computeFilesOfInterest()).first.path; final FakeProcessManager fakeProcessManager = FakeProcessManager( - onStart: (List command) { - if (command.first.endsWith('clang-tidy')) { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.first.endsWith('clang-tidy')) { return FakeProcess(exitCode: -io.ProcessSignal.sigsegv.signalNumber); } - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ); diff --git a/engine/src/flutter/tools/engine_tool/lib/src/dart_utils.dart b/engine/src/flutter/tools/engine_tool/lib/src/dart_utils.dart index 86a09acfd8d..12d42e23dac 100644 --- a/engine/src/flutter/tools/engine_tool/lib/src/dart_utils.dart +++ b/engine/src/flutter/tools/engine_tool/lib/src/dart_utils.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:io' as io; + +import 'package:collection/collection.dart'; import 'package:path/path.dart' as p; import 'environment.dart'; @@ -14,3 +17,21 @@ String findDartBinDirectory(Environment env) { String findDartBinary(Environment env) { return p.join(findDartBinDirectory(env), 'dart'); } + +/// Returns the path to `.gclient` file, or null if it cannot be found. +String? findDotGclient(Environment env) { + io.Directory directory = env.engine.srcDir; + io.File? dotGclientFile; + while (dotGclientFile == null) { + dotGclientFile = directory.listSync().whereType().firstWhereOrNull((file) { + return p.basename(file.path) == '.gclient'; + }); + + final parent = directory.parent; + if (parent.path == directory.path) { + break; + } + directory = parent; + } + return dotGclientFile?.path; +} diff --git a/engine/src/flutter/tools/engine_tool/lib/src/dependencies.dart b/engine/src/flutter/tools/engine_tool/lib/src/dependencies.dart index a135997a78e..6aff7556e4d 100644 --- a/engine/src/flutter/tools/engine_tool/lib/src/dependencies.dart +++ b/engine/src/flutter/tools/engine_tool/lib/src/dependencies.dart @@ -6,6 +6,7 @@ import 'dart:io' as io; import 'package:process_runner/process_runner.dart'; +import 'dart_utils.dart'; import 'environment.dart'; import 'logger.dart'; @@ -16,8 +17,21 @@ Future fetchDependencies(Environment environment) async { return 1; } + final dotGclientPath = findDotGclient(environment); + + if (dotGclientPath == null) { + environment.logger.error( + 'Failed to find the .gclient file. Make sure your local engine build ' + 'environment is configured as described in ' + 'https://github.com/flutter/flutter/blob/master/engine/README.md', + ); + return 1; + } + environment.logger.status('Fetching dependencies... ', newline: environment.verbose); + final dotGclient = io.File(dotGclientPath); + Spinner? spinner; ProcessRunnerResult result; try { @@ -30,6 +44,7 @@ Future fetchDependencies(Environment environment) async { runInShell: true, startMode: environment.verbose ? io.ProcessStartMode.inheritStdio : io.ProcessStartMode.normal, + workingDirectory: dotGclient.parent, ); } finally { spinner?.finish(); diff --git a/engine/src/flutter/tools/engine_tool/test/commands/fetch_command_test.dart b/engine/src/flutter/tools/engine_tool/test/commands/fetch_command_test.dart index 4fd9a7cd3d9..f9af2f5b67c 100644 --- a/engine/src/flutter/tools/engine_tool/test/commands/fetch_command_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/commands/fetch_command_test.dart @@ -25,8 +25,8 @@ void main() { final Map configs = {}; - (Environment, List>) linuxEnv(Logger logger) { - final List> runHistory = >[]; + (Environment, List) linuxEnv(Logger logger) { + final runHistory = []; return ( Environment( abi: ffi.Abi.linuxX64, @@ -38,12 +38,12 @@ void main() { ), processRunner: ProcessRunner( processManager: FakeProcessManager( - onStart: (List command) { - runHistory.add(command); + onStart: (FakeCommandLogEntry entry) { + runHistory.add(entry); return FakeProcess(); }, - onRun: (List command) { - runHistory.add(command); + onRun: (FakeCommandLogEntry entry) { + runHistory.add(entry); return io.ProcessResult(81, 0, '', ''); }, ), @@ -56,21 +56,22 @@ void main() { test('fetch command invokes gclient sync -D', () async { final Logger logger = Logger.test((_) {}); - final (Environment env, List> runHistory) = linuxEnv(logger); + final (Environment env, List runHistory) = linuxEnv(logger); final ToolCommandRunner runner = ToolCommandRunner(environment: env, configs: configs); final int result = await runner.run(['fetch']); expect(result, equals(0)); expect(runHistory.length, greaterThanOrEqualTo(1)); - expect(runHistory[0], containsAllInOrder(['gclient', 'sync', '-D'])); + expect(runHistory[0].command, containsAllInOrder(['gclient', 'sync', '-D'])); }); test('fetch command has sync alias', () async { final Logger logger = Logger.test((_) {}); - final (Environment env, List> runHistory) = linuxEnv(logger); + final (Environment env, List runHistory) = linuxEnv(logger); final ToolCommandRunner runner = ToolCommandRunner(environment: env, configs: configs); final int result = await runner.run(['sync']); expect(result, equals(0)); expect(runHistory.length, greaterThanOrEqualTo(1)); - expect(runHistory[0], containsAllInOrder(['gclient', 'sync', '-D'])); + expect(runHistory[0].command, containsAllInOrder(['gclient', 'sync', '-D'])); + expect(runHistory[0].workingDirectory, env.engine.flutterDir.parent.parent.parent.path); }); } diff --git a/engine/src/flutter/tools/engine_tool/test/commands/format_command_test.dart b/engine/src/flutter/tools/engine_tool/test/commands/format_command_test.dart index fe5dc962880..60c180da700 100644 --- a/engine/src/flutter/tools/engine_tool/test/commands/format_command_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/commands/format_command_test.dart @@ -222,11 +222,11 @@ FakeProcessManager _formatProcessManager({ return FakeProcessManager( canRun: canRun ?? (Object? exe, {String? workingDirectory}) => true, onRun: - (List cmd) => switch (cmd) { + (FakeCommandLogEntry entry) => switch (entry.command) { _ => failUnknown ? io.ProcessResult(1, 1, '', '') : success, }, onStart: - (List cmd) => switch (cmd) { + (FakeCommandLogEntry entry) => switch (entry.command) { [final String exe, final String fmt, ...final List rest] when exe.endsWith('dart') && fmt.endsWith('ci/bin/format.dart') && diff --git a/engine/src/flutter/tools/engine_tool/test/commands/lint_command_test.dart b/engine/src/flutter/tools/engine_tool/test/commands/lint_command_test.dart index 2bcebb6de3a..8b79f80a48e 100644 --- a/engine/src/flutter/tools/engine_tool/test/commands/lint_command_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/commands/lint_command_test.dart @@ -30,11 +30,11 @@ void main() { ), processRunner: ProcessRunner( processManager: FakeProcessManager( - onStart: (command) { - runHistory.add(command); + onStart: (FakeCommandLogEntry entry) { + runHistory.add(entry.command); return FakeProcess(); }, - onRun: (command) { + onRun: (_) { // Should not be executed. assert(false); return io.ProcessResult(81, 1, '', ''); diff --git a/engine/src/flutter/tools/engine_tool/test/commands/run_command_test.dart b/engine/src/flutter/tools/engine_tool/test/commands/run_command_test.dart index cf374076581..324a4d76399 100644 --- a/engine/src/flutter/tools/engine_tool/test/commands/run_command_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/commands/run_command_test.dart @@ -153,21 +153,21 @@ void main() { // Be very permissive on process execution, and check usage below instead. final permissiveProcessManager = FakeProcessManager( canRun: (_, {workingDirectory}) => true, - onRun: (command) { - commandsRun.add(command); + onRun: (FakeCommandLogEntry entry) { + commandsRun.add(entry.command); return io.ProcessResult(81, 0, '', ''); }, - onStart: (command) { - commandsRun.add(command); - for (final entry in interceptCommands) { - if (command.first.endsWith(entry.$1)) { - final result = entry.$2(command); + onStart: (FakeCommandLogEntry entry) { + commandsRun.add(entry.command); + for (final intercept in interceptCommands) { + if (entry.command.first.endsWith(intercept.$1)) { + final result = intercept.$2(entry.command); if (result != null) { return result; } } } - switch (command) { + switch (entry.command) { case ['flutter', 'devices', '--machine', ..._]: return FakeProcess(stdout: jsonEncode(attachedDevices)); default: diff --git a/engine/src/flutter/tools/engine_tool/test/proc_utils_test.dart b/engine/src/flutter/tools/engine_tool/test/proc_utils_test.dart index 9a647dd64c2..462a8eaeeea 100644 --- a/engine/src/flutter/tools/engine_tool/test/proc_utils_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/proc_utils_test.dart @@ -38,9 +38,9 @@ void main() { ), processRunner: ProcessRunner( processManager: FakeProcessManager( - onStart: (List command) { - runHistory.add(command); - switch (command) { + onStart: (FakeCommandLogEntry entry) { + runHistory.add(entry.command); + switch (entry.command) { case ['success']: return FakeProcess(stdout: 'stdout success'); case ['failure']: @@ -49,7 +49,7 @@ void main() { return FakeProcess(); } }, - onRun: (List command) { + onRun: (FakeCommandLogEntry entry) { // Should not be executed. assert(false); return io.ProcessResult(81, 1, '', ''); diff --git a/engine/src/flutter/tools/engine_tool/test/src/utils.dart b/engine/src/flutter/tools/engine_tool/test/src/utils.dart index 62188a07c4f..b0739af8957 100644 --- a/engine/src/flutter/tools/engine_tool/test/src/utils.dart +++ b/engine/src/flutter/tools/engine_tool/test/src/utils.dart @@ -73,18 +73,18 @@ class TestEnvironment { ), processRunner: ProcessRunner( processManager: FakeProcessManager( - onStart: (List command) { - final FakeProcess processResult = _getCannedResult(command, cannedProcesses); + onStart: (FakeCommandLogEntry entry) { + final FakeProcess processResult = _getCannedResult(entry.command, cannedProcesses); processResult.exitCode.then((int exitCode) { - processHistory.add(ExecutedProcess(command, processResult, exitCode)); + processHistory.add(ExecutedProcess(entry.command, processResult, exitCode)); }); return processResult; }, - onRun: (List command) { - final io.ProcessResult result = _getCannedProcessResult(command, cannedProcesses); + onRun: (FakeCommandLogEntry entry) { + final io.ProcessResult result = _getCannedProcessResult(entry.command, cannedProcesses); processHistory.add( ExecutedProcess( - command, + entry.command, FakeProcess( exitCode: result.exitCode, stdout: result.stdout as String, diff --git a/engine/src/flutter/tools/engine_tool/test/worker_pool_test.dart b/engine/src/flutter/tools/engine_tool/test/worker_pool_test.dart index c464637b100..80434dbfc87 100644 --- a/engine/src/flutter/tools/engine_tool/test/worker_pool_test.dart +++ b/engine/src/flutter/tools/engine_tool/test/worker_pool_test.dart @@ -76,9 +76,9 @@ void main() { platform: FakePlatform(operatingSystem: Platform.macOS, pathSeparator: '/'), processRunner: ProcessRunner( processManager: FakeProcessManager( - onStart: (List command) { - runHistory.add(command); - switch (command) { + onStart: (FakeCommandLogEntry entry) { + runHistory.add(entry.command); + switch (entry.command) { case ['success']: return FakeProcess(stdout: 'stdout success'); case ['failure']: @@ -87,7 +87,7 @@ void main() { return FakeProcess(); } }, - onRun: (List command) { + onRun: (FakeCommandLogEntry entry) { // Should not be executed. assert(false); return io.ProcessResult(81, 1, '', ''); diff --git a/engine/src/flutter/tools/pkg/engine_build_configs/test/build_config_runner_test.dart b/engine/src/flutter/tools/pkg/engine_build_configs/test/build_config_runner_test.dart index 170595a3934..81312938162 100644 --- a/engine/src/flutter/tools/pkg/engine_build_configs/test/build_config_runner_test.dart +++ b/engine/src/flutter/tools/pkg/engine_build_configs/test/build_config_runner_test.dart @@ -827,11 +827,11 @@ FakeProcessManager _fakeProcessManager({ return FakeProcessManager( canRun: canRun ?? (Object? exe, {String? workingDirectory}) => true, onRun: - (List cmd) => switch (cmd) { + (FakeCommandLogEntry entry) => switch (entry.command) { _ => failUnknown ? io.ProcessResult(1, 1, '', '') : success, }, onStart: - (List cmd) => switch (cmd) { + (FakeCommandLogEntry entry) => switch (entry.command) { [final String exe, ...] when exe.endsWith('gn') => fakeProcess(gnResult), [final String exe, ...] when exe.endsWith('bootstrap') => fakeProcess(bootstrapResult), [final String exe, ...] when exe.endsWith('ninja') => fakeProcess(ninjaResult), diff --git a/engine/src/flutter/tools/pkg/git_repo_tools/test/git_repo_tools_test.dart b/engine/src/flutter/tools/pkg/git_repo_tools/test/git_repo_tools_test.dart index a5d4bbc5089..9727cf9379f 100644 --- a/engine/src/flutter/tools/pkg/git_repo_tools/test/git_repo_tools_test.dart +++ b/engine/src/flutter/tools/pkg/git_repo_tools/test/git_repo_tools_test.dart @@ -14,25 +14,25 @@ void main() { test('returns non-deleted files which differ from merge-base with main', () async { final Fixture fixture = Fixture( processManager: FakeProcessManager( - onStart: (List command) { + onStart: (FakeCommandLogEntry entry) { // Succeed calling "git merge-base --fork-point FETCH_HEAD HEAD". - if (command.join(' ').startsWith('git merge-base --fork-point')) { + if (entry.command.join(' ').startsWith('git merge-base --fork-point')) { return FakeProcess(stdout: fakeShaHash); } // Succeed calling "git fetch upstream main". - if (command.join(' ') == 'git fetch upstream main') { + if (entry.command.join(' ') == 'git fetch upstream main') { return FakeProcess(); } // Succeed calling "git diff --name-only --diff-filter=ACMRT fake-sha-hash". - if (command.join(' ') == + if (entry.command.join(' ') == 'git diff --name-only --diff-filter=ACMRT --relative $fakeShaHash') { return FakeProcess(stdout: 'file1\nfile2'); } // Otherwise, fail. - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -50,26 +50,26 @@ void main() { test('returns non-deleted files which differ from default merge-base', () async { final Fixture fixture = Fixture( processManager: FakeProcessManager( - onStart: (List command) { - if (command.join(' ').startsWith('git merge-base --fork-point')) { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.join(' ').startsWith('git merge-base --fork-point')) { return FakeProcess(exitCode: 1); } - if (command.join(' ').startsWith('git merge-base')) { + if (entry.command.join(' ').startsWith('git merge-base')) { return FakeProcess(stdout: fakeShaHash); } - if (command.join(' ') == 'git fetch upstream main') { + if (entry.command.join(' ') == 'git fetch upstream main') { return FakeProcess(); } - if (command.join(' ') == + if (entry.command.join(' ') == 'git diff --name-only --diff-filter=ACMRT --relative $fakeShaHash') { return FakeProcess(stdout: 'file1\nfile2'); } // Otherwise, fail. - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -87,18 +87,18 @@ void main() { test('returns non-deleted files which differ from HEAD', () async { final Fixture fixture = Fixture( processManager: FakeProcessManager( - onStart: (List command) { - if (command.join(' ') == 'git fetch upstream main') { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.join(' ') == 'git fetch upstream main') { return FakeProcess(); } - if (command.join(' ') == + if (entry.command.join(' ') == 'git diff-tree --no-commit-id --name-only --diff-filter=ACMRT --relative -r HEAD') { return FakeProcess(stdout: 'file1\nfile2'); } // Otherwise, fail. - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -116,26 +116,26 @@ void main() { test('returns non-deleted files which differ from HEAD when merge-base fails', () async { final Fixture fixture = Fixture( processManager: FakeProcessManager( - onStart: (List command) { - if (command.join(' ') == 'git fetch upstream main') { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.join(' ') == 'git fetch upstream main') { return FakeProcess(); } - if (command.join(' ') == + if (entry.command.join(' ') == 'git diff-tree --no-commit-id --name-only --diff-filter=ACMRT --relative -r HEAD') { return FakeProcess(stdout: 'file1\nfile2'); } - if (command.join(' ').startsWith('git merge-base --fork-point')) { + if (entry.command.join(' ').startsWith('git merge-base --fork-point')) { return FakeProcess(exitCode: 1); } - if (command.join(' ').startsWith('git merge-base')) { + if (entry.command.join(' ').startsWith('git merge-base')) { return FakeProcess(stdout: fakeShaHash); } // Otherwise, fail. - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), ); @@ -153,26 +153,26 @@ void main() { test('verbose output is captured', () async { final Fixture fixture = Fixture( processManager: FakeProcessManager( - onStart: (List command) { - if (command.join(' ').startsWith('git merge-base --fork-point')) { + onStart: (FakeCommandLogEntry entry) { + if (entry.command.join(' ').startsWith('git merge-base --fork-point')) { return FakeProcess(exitCode: 1); } - if (command.join(' ').startsWith('git merge-base')) { + if (entry.command.join(' ').startsWith('git merge-base')) { return FakeProcess(stdout: fakeShaHash); } - if (command.join(' ') == 'git fetch upstream main') { + if (entry.command.join(' ') == 'git fetch upstream main') { return FakeProcess(); } - if (command.join(' ') == + if (entry.command.join(' ') == 'git diff --name-only --diff-filter=ACMRT --relative $fakeShaHash') { return FakeProcess(stdout: 'file1\nfile2'); } // Otherwise, fail. - return FakeProcessManager.unhandledStart(command); + return FakeProcessManager.unhandledStart(entry); }, ), verbose: true, diff --git a/engine/src/flutter/tools/pkg/process_fakes/lib/process_fakes.dart b/engine/src/flutter/tools/pkg/process_fakes/lib/process_fakes.dart index cec2b6f2deb..981bcaad940 100644 --- a/engine/src/flutter/tools/pkg/process_fakes/lib/process_fakes.dart +++ b/engine/src/flutter/tools/pkg/process_fakes/lib/process_fakes.dart @@ -14,21 +14,21 @@ final class FakeProcessManager implements ProcessManager { /// /// If either is not provided, it throws an [UnsupportedError] when called. FakeProcessManager({ - io.ProcessResult Function(List command) onRun = unhandledRun, - io.Process Function(List command) onStart = unhandledStart, + io.ProcessResult Function(FakeCommandLogEntry entry) onRun = unhandledRun, + io.Process Function(FakeCommandLogEntry entry) onStart = unhandledStart, bool Function(Object?, {String? workingDirectory}) canRun = unhandledCanRun, }) : _onRun = onRun, _onStart = onStart, _canRun = canRun; /// A default implementation of [onRun] that throws an [UnsupportedError]. - static io.ProcessResult unhandledRun(List command) { - throw UnsupportedError('Unhandled run: ${command.join(' ')}'); + static io.ProcessResult unhandledRun(FakeCommandLogEntry entry) { + throw UnsupportedError('Unhandled run: ${entry.command.join(' ')}'); } /// A default implementation of [onStart] that throws an [UnsupportedError]. - static io.Process unhandledStart(List command) { - throw UnsupportedError('Unhandled start: ${command.join(' ')}'); + static io.Process unhandledStart(FakeCommandLogEntry entry) { + throw UnsupportedError('Unhandled start: ${entry.command.join(' ')}'); } /// A default implementation of [canRun] that returns `true`. @@ -36,8 +36,8 @@ final class FakeProcessManager implements ProcessManager { return true; } - final io.ProcessResult Function(List command) _onRun; - final io.Process Function(List command) _onStart; + final io.ProcessResult Function(FakeCommandLogEntry entry) _onRun; + final io.Process Function(FakeCommandLogEntry entry) _onStart; final bool Function(Object?, {String? workingDirectory}) _canRun; @override @@ -79,7 +79,17 @@ final class FakeProcessManager implements ProcessManager { Encoding stdoutEncoding = io.systemEncoding, Encoding stderrEncoding = io.systemEncoding, }) { - return _onRun(command.map((Object o) => '$o').toList()); + return _onRun( + FakeCommandLogEntry( + command, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + ), + ); } @override @@ -91,10 +101,57 @@ final class FakeProcessManager implements ProcessManager { bool runInShell = false, io.ProcessStartMode mode = io.ProcessStartMode.normal, }) async { - return _onStart(command.map((Object o) => '$o').toList()); + return _onStart( + FakeCommandLogEntry( + command, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: null, + stderrEncoding: null, + ), + ); } } +/// Contains information about [ProcessManager.start] and [ProcessManager.run] +/// invocations. +final class FakeCommandLogEntry { + /// Creates a log entry for a single process invocation. + FakeCommandLogEntry( + List command, { + required this.workingDirectory, + required this.environment, + required this.includeParentEnvironment, + required this.runInShell, + required this.stdoutEncoding, + required this.stderrEncoding, + }) : command = command.map((o) => '$o').toList(); + + /// The command passed to the [ProcessManager]. + final List command; + + /// The working directory passed to the [ProcessManager]. + final String? workingDirectory; + + /// The environment variables at the time [ProcessManager] was called. + final Map? environment; + + /// Whether the parent environment variables were included when spawning the + /// child process. + final bool includeParentEnvironment; + + /// When the child was spawned in a shell environment. + final bool runInShell; + + /// The encoding used by `stdout`. + final Encoding? stdoutEncoding; + + /// The encoding used by `stderr`. + final Encoding? stderrEncoding; +} + /// An incomplete fake of [io.Process] that allows control for testing. final class FakeProcess implements io.Process { /// Creates a fake process that returns the given [exitCode] and out/err.