Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 9aad0e9

Browse files
authored
[et] Allow users to update dependencies (#51177)
Allow users to update dependencies. Examples: * `et fetch` Fetch dependencies In the future, `et build` will update dependencies if it detects that they have changed. Also: * Updates the status in the README * Adds instructions on how to run tests * Fixes `et run`'s description * Makes the `--verbose` flag global
1 parent a124e50 commit 9aad0e9

11 files changed

+217
-30
lines changed

testing/litetest/lib/src/matchers.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ Matcher hasMatch(String pattern) => (dynamic d) {
132132
}
133133
};
134134

135-
/// Gives a matcher that asserts that the value being matched is a List<String>
136-
/// that contains the entries in `pattern` in order. There may be values
137-
/// that are not in the pattern interleaved.
135+
/// Gives a matcher that asserts that the value being matched is a
136+
/// `List<String>` that contains the entries in `pattern` in order.
137+
/// There may be values that are not in the pattern interleaved.
138138
Matcher containsStringsInOrder(List<String> pattern) => (dynamic d) {
139139
expect(d, isInstanceOf<List<String>>());
140140
final List<String> input = d as List<String>;
@@ -148,6 +148,18 @@ Matcher containsStringsInOrder(List<String> pattern) => (dynamic d) {
148148
}
149149
}
150150
if (cursor < pattern.length) {
151-
Expect.fail('Did not find ${pattern[cursor]} in $d}');
151+
Expect.fail('Did not find ${pattern[cursor]} in $d');
152+
}
153+
};
154+
155+
/// Gives a matcher that asserts that the value being matched is a
156+
/// `List<String>` that does not contain any of the values in `unexpected`.
157+
Matcher doesNotContainAny(List<String> unexpected) => (dynamic d) {
158+
expect(d, isInstanceOf<List<String>>());
159+
final List<String> input = d as List<String>;
160+
for (final String string in input) {
161+
if (unexpected.contains(string)) {
162+
Expect.fail("String '$d' is unexpected");
163+
}
152164
}
153165
};

tools/engine_tool/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ before it will work.
1414
The tool has the following commands.
1515

1616
* `help` - Prints helpful information about commands and usage.
17+
* `build` - Builds the Flutter engine.
18+
* `fetch` - Downloads Flutter engine dependencies.
1719
* `format` - Formats files in the engine tree using various off-the-shelf
1820
formatters.
1921
* `run` - Runs a flutter application with a local build of the engine.
@@ -27,7 +29,7 @@ GitHub issue [here](https://github.com/flutter/flutter/issues/132807). Some
2729
desirable new features would do the following:
2830

2931
* Add a `doctor` command.
30-
* Update the engine checkout so that engine developers no longer have to remeber
32+
* Update the engine checkout so that engine developers no longer have to remember
3133
to run `gclient sync -D`.
3234
* Build and test the engine using CI configurations locally, with the
3335
possibility to override or add new build options and targets.
@@ -61,3 +63,9 @@ implementation, then write a fake implementation.
6163
* *Begin with the end in mind* - Start working from what the interface provided
6264
by this tool *should* be, then modify underlying scripts and tools to provide
6365
APIs to support that.
66+
67+
Run tests using `//flutter/testing/run_tests.py`:
68+
69+
```shell
70+
testing/run_tests.py --type dart-host --dart-host-filter flutter/tools/engine_tool
71+
```

tools/engine_tool/lib/src/commands/build_command.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ final class BuildCommand extends CommandBase {
1717
}) {
1818
builds = runnableBuilds(environment, configs);
1919
debugCheckBuilds(builds);
20-
// Add options here that are common to all queries.
2120
argParser.addOption(
2221
configFlag,
2322
abbr: 'c',
@@ -53,6 +52,7 @@ final class BuildCommand extends CommandBase {
5352
return 1;
5453
}
5554

55+
// TODO(loic-sharma): Fetch dependencies if needed.
5656
return runBuild(environment, build);
5757
}
5858
}

tools/engine_tool/lib/src/commands/command_runner.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import 'package:engine_build_configs/engine_build_configs.dart';
77

88
import '../environment.dart';
99
import 'build_command.dart';
10+
import 'fetch_command.dart';
11+
import 'flags.dart';
1012
import 'format_command.dart';
1113
import 'query_command.dart';
1214
import 'run_command.dart';
@@ -22,14 +24,20 @@ final class ToolCommandRunner extends CommandRunner<int> {
2224
required this.configs,
2325
}) : super(toolName, toolDescription, usageLineLength: _usageLineLength) {
2426
final List<Command<int>> commands = <Command<int>>[
25-
FormatCommand(
26-
environment: environment,
27-
),
27+
FetchCommand(environment: environment),
28+
FormatCommand(environment: environment),
2829
QueryCommand(environment: environment, configs: configs),
2930
BuildCommand(environment: environment, configs: configs),
3031
RunCommand(environment: environment, configs: configs),
3132
];
3233
commands.forEach(addCommand);
34+
35+
argParser.addFlag(
36+
verboseFlag,
37+
abbr: 'v',
38+
help: 'Prints verbose output',
39+
negatable: false,
40+
);
3341
}
3442

3543
/// The name of the tool as reported in the tool's usage and help
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import '../dependencies.dart';
6+
import 'command.dart';
7+
import 'flags.dart';
8+
9+
/// The root 'fetch' command.
10+
final class FetchCommand extends CommandBase {
11+
/// Constructs the 'fetch' command.
12+
FetchCommand({
13+
required super.environment,
14+
});
15+
16+
@override
17+
String get name => 'fetch';
18+
19+
@override
20+
String get description => "Download the Flutter engine's dependencies";
21+
22+
@override
23+
List<String> get aliases => const <String>['sync'];
24+
25+
@override
26+
Future<int> run() {
27+
final bool verbose = globalResults![verboseFlag] as bool;
28+
return fetchDependencies(environment, verbose: verbose);
29+
}
30+
}

tools/engine_tool/lib/src/commands/format_command.dart

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@ final class FormatCommand extends CommandBase {
4747
abbr: 'q',
4848
help: 'Silences all log messages except for errors and warnings',
4949
negatable: false,
50-
)
51-
..addFlag(
52-
verboseFlag,
53-
abbr: 'v',
54-
help: 'Prints verbose output',
55-
negatable: false,
5650
);
5751
}
5852

@@ -67,7 +61,7 @@ final class FormatCommand extends CommandBase {
6761
final bool all = argResults![allFlag]! as bool;
6862
final bool dryRun = argResults![dryRunFlag]! as bool;
6963
final bool quiet = argResults![quietFlag]! as bool;
70-
final bool verbose = argResults![verboseFlag]! as bool;
64+
final bool verbose = globalResults![verboseFlag] as bool;
7165
final String formatPath = p.join(
7266
environment.engine.flutterDir.path, 'ci', 'bin', 'format.dart',
7367
);

tools/engine_tool/lib/src/commands/query_command.dart

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,6 @@ final class QueryCommand extends CommandBase {
3636
if (entry.value.canRunOn(environment.platform))
3737
entry.key: entry.value.path,
3838
},
39-
)
40-
..addFlag(
41-
verboseFlag,
42-
abbr: 'v',
43-
help: 'Respond to queries with extra information',
44-
negatable: false,
4539
);
4640

4741
addSubcommand(QueryBuildersCommand(
@@ -85,7 +79,7 @@ final class QueryBuildersCommand extends CommandBase {
8579
// current platform.
8680
final bool all = parent!.argResults![allFlag]! as bool;
8781
final String? builderName = parent!.argResults![builderFlag] as String?;
88-
final bool verbose = parent!.argResults![verboseFlag] as bool;
82+
final bool verbose = globalResults![verboseFlag]! as bool;
8983
if (!verbose) {
9084
environment.logger.status(
9185
'Add --verbose to see detailed information about each builder',

tools/engine_tool/lib/src/commands/run_command.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ final class RunCommand extends CommandBase {
4646
String get name => 'run';
4747

4848
@override
49-
String get description => 'Run a flutter app with a local engine build'
49+
String get description => 'Run a Flutter app with a local engine build. '
5050
'All arguments after -- are forwarded to flutter run, e.g.: '
51-
'et run -- --profile'
52-
'et run -- -d macos'
51+
'et run -- --profile '
52+
'et run -- -d macos '
5353
'See `flutter run --help` for a listing';
5454

5555
Build? _lookup(String configName) {
@@ -123,7 +123,7 @@ final class RunCommand extends CommandBase {
123123
@override
124124
Future<int> run() async {
125125
if (!environment.processRunner.processManager.canRun('flutter')) {
126-
environment.logger.error('Cannot find flutter command in your path');
126+
environment.logger.error('Cannot find the flutter command in your path');
127127
return 1;
128128
}
129129
final String? configName = await _selectTargetConfig();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io' as io;
6+
7+
import 'package:process_runner/process_runner.dart';
8+
9+
import 'environment.dart';
10+
import 'logger.dart';
11+
12+
/// Update Flutter engine dependencies. Returns an exit code.
13+
Future<int> fetchDependencies(
14+
Environment environment, {
15+
bool verbose = false,
16+
}) async {
17+
if (!environment.processRunner.processManager.canRun('gclient')) {
18+
environment.logger.error('Cannot find the gclient command in your path');
19+
return 1;
20+
}
21+
22+
environment.logger.status('Fetching dependencies... ', newline: verbose);
23+
24+
Spinner? spinner;
25+
ProcessRunnerResult result;
26+
try {
27+
if (!verbose) {
28+
spinner = environment.logger.startSpinner();
29+
}
30+
31+
result = await environment.processRunner.runProcess(
32+
<String>[
33+
'gclient',
34+
'sync',
35+
'-D',
36+
],
37+
runInShell: true,
38+
startMode: verbose
39+
? io.ProcessStartMode.inheritStdio
40+
: io.ProcessStartMode.normal,
41+
);
42+
} finally {
43+
spinner?.finish();
44+
}
45+
46+
if (result.exitCode != 0) {
47+
environment.logger.error('Fetching dependencies failed.');
48+
49+
// Verbose mode already logged output by making the child process inherit
50+
// this process's stdio handles.
51+
if (!verbose) {
52+
environment.logger.error('Output:\n${result.output}');
53+
}
54+
}
55+
56+
return result.exitCode;
57+
}

tools/engine_tool/test/build_command_test.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ void main() {
134134
]);
135135
expect(result, equals(0));
136136
expect(runHistory.length, greaterThanOrEqualTo(3));
137-
expect(runHistory[2].length, greaterThanOrEqualTo(2));
138-
expect(runHistory[2][0], contains('python3'));
139-
expect(runHistory[2][1], contains('gen/script.py'));
137+
expect(
138+
runHistory[2],
139+
containsStringsInOrder(<String>['python3', 'gen/script.py']),
140+
);
140141
});
141142

142143
test('build command does not invoke tests', () async {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ffi' as ffi show Abi;
6+
import 'dart:io' as io;
7+
8+
import 'package:engine_build_configs/engine_build_configs.dart';
9+
import 'package:engine_repo_tools/engine_repo_tools.dart';
10+
import 'package:engine_tool/src/commands/command_runner.dart';
11+
import 'package:engine_tool/src/environment.dart';
12+
import 'package:engine_tool/src/logger.dart';
13+
import 'package:litetest/litetest.dart';
14+
import 'package:platform/platform.dart';
15+
import 'package:process_fakes/process_fakes.dart';
16+
import 'package:process_runner/process_runner.dart';
17+
18+
void main() {
19+
final Engine? engine = Engine.tryFindWithin();
20+
if (engine == null) {
21+
io.stderr.writeln('The current working directory is not a Flutter engine');
22+
io.exitCode = 1;
23+
return;
24+
}
25+
26+
final Map<String, BuilderConfig> configs = <String, BuilderConfig>{};
27+
28+
(Environment, List<List<String>>) linuxEnv(Logger logger) {
29+
final List<List<String>> runHistory = <List<String>>[];
30+
return (
31+
Environment(
32+
abi: ffi.Abi.linuxX64,
33+
engine: engine,
34+
platform: FakePlatform(operatingSystem: Platform.linux),
35+
processRunner: ProcessRunner(
36+
processManager: FakeProcessManager(onStart: (List<String> command) {
37+
runHistory.add(command);
38+
return FakeProcess();
39+
}, onRun: (List<String> command) {
40+
runHistory.add(command);
41+
return io.ProcessResult(81, 0, '', '');
42+
}),
43+
),
44+
logger: logger,
45+
),
46+
runHistory
47+
);
48+
}
49+
50+
test('fetch command invokes gclient sync -D', () async {
51+
final Logger logger = Logger.test();
52+
final (Environment env, List<List<String>> runHistory) = linuxEnv(logger);
53+
final ToolCommandRunner runner = ToolCommandRunner(
54+
environment: env,
55+
configs: configs,
56+
);
57+
final int result =
58+
await runner.run(<String>['fetch']);
59+
expect(result, equals(0));
60+
expect(runHistory.length, greaterThanOrEqualTo(1));
61+
expect(
62+
runHistory[0],
63+
containsStringsInOrder(<String>['gclient', 'sync', '-D']),
64+
);
65+
});
66+
67+
test('fetch command has sync alias', () async {
68+
final Logger logger = Logger.test();
69+
final (Environment env, List<List<String>> runHistory) = linuxEnv(logger);
70+
final ToolCommandRunner runner = ToolCommandRunner(
71+
environment: env,
72+
configs: configs,
73+
);
74+
final int result =
75+
await runner.run(<String>['sync']);
76+
expect(result, equals(0));
77+
expect(runHistory.length, greaterThanOrEqualTo(1));
78+
expect(
79+
runHistory[0],
80+
containsStringsInOrder(<String>['gclient', 'sync', '-D']),
81+
);
82+
});
83+
}

0 commit comments

Comments
 (0)