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

Commit 65ac4bf

Browse files
authored
Include stdout on a failed gn desc call, and test for it. (#52863)
Fixes flutter/flutter#148431, in that full error output is now shown. I also filed an additional issue for how we could do better: flutter/flutter#148442.
1 parent e6e37b4 commit 65ac4bf

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

tools/engine_tool/lib/src/gn.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ interface class Gn {
6767
result = JsonObject.parse(process.stdout);
6868
} on FormatException catch (e) {
6969
_environment.logger.fatal(
70-
'Failed to parse JSON output from `gn desc`:\n$e',
70+
'Failed to parse JSON output from `gn desc`:\n$e\n${process.stdout}',
7171
);
7272
}
7373

@@ -136,6 +136,10 @@ sealed class BuildTarget {
136136
@mustBeOverridden
137137
@override
138138
int get hashCode;
139+
140+
@mustBeOverridden
141+
@override
142+
String toString();
139143
}
140144

141145
/// A build target that produces a [shared library][] or [static library][].
@@ -158,6 +162,9 @@ final class LibraryBuildTarget extends BuildTarget {
158162

159163
@override
160164
int get hashCode => Object.hash(label, testOnly);
165+
166+
@override
167+
String toString() => 'LibraryBuildTarget($label, testOnly=$testOnly)';
161168
}
162169

163170
/// A build target that produces an [executable][] program.
@@ -184,4 +191,7 @@ final class ExecutableBuildTarget extends BuildTarget {
184191

185192
@override
186193
int get hashCode => Object.hash(label, testOnly, executable);
194+
195+
@override
196+
String toString() => 'ExecutableBuildTarget($label, testOnly=$testOnly, executable=$executable)';
187197
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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 'package:engine_tool/src/gn.dart';
6+
import 'package:engine_tool/src/label.dart';
7+
import 'package:litetest/litetest.dart';
8+
9+
import 'utils.dart';
10+
11+
void main() {
12+
test('gn.desc handles a non-zero exit code', () async {
13+
final TestEnvironment testEnv = TestEnvironment.withTestEngine(
14+
cannedProcesses: <CannedProcess>[
15+
CannedProcess(
16+
(List<String> command) => command.contains('desc'),
17+
exitCode: 1,
18+
stdout: 'stdout',
19+
stderr: 'stderr',
20+
),
21+
],
22+
);
23+
try {
24+
final Gn gn = Gn.fromEnvironment(testEnv.environment);
25+
await gn.desc('out/Release', TargetPattern('//foo', 'bar'));
26+
fail('Expected an exception');
27+
} catch (e) {
28+
final String message = '$e';
29+
expect(message, contains('Failed to run'));
30+
expect(message, contains('exit code 1'));
31+
expect(message, contains('STDOUT:\nstdout'));
32+
expect(message, contains('STDERR:\nstderr'));
33+
} finally {
34+
testEnv.cleanup();
35+
}
36+
});
37+
38+
test('gn.desc handles unparseable stdout', () async {
39+
final TestEnvironment testEnv = TestEnvironment.withTestEngine(
40+
cannedProcesses: <CannedProcess>[
41+
CannedProcess(
42+
(List<String> command) => command.contains('desc'),
43+
stdout: 'not json',
44+
),
45+
],
46+
);
47+
try {
48+
final Gn gn = Gn.fromEnvironment(testEnv.environment);
49+
await gn.desc('out/Release', TargetPattern('//foo', 'bar'));
50+
fail('Expected an exception');
51+
} catch (e) {
52+
final String message = '$e';
53+
expect(message, contains('Failed to parse JSON'));
54+
expect(message, contains('not json'));
55+
} finally {
56+
testEnv.cleanup();
57+
}
58+
});
59+
60+
test('gn.desc parses build targets', () async {
61+
final TestEnvironment testEnv = TestEnvironment.withTestEngine(
62+
cannedProcesses: <CannedProcess>[
63+
CannedProcess(
64+
(List<String> command) => command.contains('desc'),
65+
stdout: '''
66+
{
67+
"//foo/bar:baz_test": {
68+
"outputs": ["//out/host_debug/foo/bar/baz_test"],
69+
"testonly": true,
70+
"type": "executable"
71+
},
72+
"//foo/bar:baz_shared_library": {
73+
"testonly": false,
74+
"type": "shared_library"
75+
},
76+
"//foo/bar:baz_static_library": {
77+
"testonly": false,
78+
"type": "static_library"
79+
}
80+
}
81+
''',
82+
),
83+
],
84+
);
85+
try {
86+
final Gn gn = Gn.fromEnvironment(testEnv.environment);
87+
final List<BuildTarget> targets = await gn.desc('out/Release', TargetPattern('//foo', 'bar'));
88+
expect(targets, hasLength(3));
89+
90+
// There should be exactly one binary test target and two library targets.
91+
final ExecutableBuildTarget testTarget = targets.whereType<ExecutableBuildTarget>().single;
92+
expect(testTarget, ExecutableBuildTarget(
93+
label: Label('//foo/bar', 'baz_test'),
94+
testOnly: true,
95+
executable: 'out/host_debug/foo/bar/baz_test',
96+
));
97+
98+
final List<LibraryBuildTarget> libraryTargets = targets.whereType<LibraryBuildTarget>().toList();
99+
expect(libraryTargets, hasLength(2));
100+
expect(libraryTargets.contains(LibraryBuildTarget(
101+
label: Label('//foo/bar', 'baz_shared_library'),
102+
testOnly: false,
103+
)), isTrue);
104+
expect(libraryTargets.contains(LibraryBuildTarget(
105+
label: Label('//foo/bar', 'baz_static_library'),
106+
testOnly: false,
107+
)), isTrue);
108+
} finally {
109+
testEnv.cleanup();
110+
}
111+
});
112+
}

0 commit comments

Comments
 (0)