Skip to content

Commit f221ad1

Browse files
Add basic desktop linux checks (flutter#31873)
1 parent d4d10da commit f221ad1

File tree

5 files changed

+258
-4
lines changed

5 files changed

+258
-4
lines changed

.cirrus.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,14 @@ task:
113113
env:
114114
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
115115
GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[1c140257edc48f5578fa5a0e5038b84c8e53270c405efa5a8e35ea303a4e0d135853989f448f72136206de854d17fbec]
116-
test_script: ./dev/bots/firebase_testlab.sh
116+
test_script:
117+
- echo "$CIRRUS_CHANGE_MESSAGE" > /tmp/cirrus_change_message.txt
118+
- echo "$CIRRUS_COMMIT_MESSAGE" > /tmp/cirrus_commit_message.txt
119+
- export CIRRUS_CHANGE_MESSAGE=""
120+
- export CIRRUS_COMMIT_MESSAGE=""
121+
- ./dev/bots/firebase_testlab.sh
122+
- export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt`
123+
- export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt`
117124

118125
task:
119126
use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == ''

packages/flutter_tools/lib/src/doctor.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import 'base/user_messages.dart';
1919
import 'base/utils.dart';
2020
import 'base/version.dart';
2121
import 'cache.dart';
22+
import 'desktop.dart';
2223
import 'device.dart';
2324
import 'fuchsia/fuchsia_workflow.dart';
2425
import 'globals.dart';
2526
import 'intellij/intellij.dart';
2627
import 'ios/ios_workflow.dart';
2728
import 'ios/plist_utils.dart';
29+
import 'linux/linux_doctor.dart';
2830
import 'linux/linux_workflow.dart';
2931
import 'macos/cocoapods_validator.dart';
3032
import 'macos/macos_workflow.dart';
@@ -69,12 +71,19 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
6971
if (iosWorkflow.appliesToHostPlatform)
7072
_validators.add(iosValidator);
7173

72-
if (windowsWorkflow.appliesToHostPlatform)
73-
_validators.add(visualStudioValidator);
74-
7574
if (webWorkflow.appliesToHostPlatform)
7675
_validators.add(const WebValidator());
7776

77+
// Add desktop doctors to workflow if the flag is enabled.
78+
if (flutterDesktopEnabled) {
79+
if (linuxWorkflow.appliesToHostPlatform) {
80+
_validators.add(LinuxDoctorValidator());
81+
}
82+
if (windowsWorkflow.appliesToHostPlatform) {
83+
_validators.add(visualStudioValidator);
84+
}
85+
}
86+
7887
final List<DoctorValidator> ideValidators = <DoctorValidator>[];
7988
ideValidators.addAll(AndroidStudioValidator.allValidators);
8089
ideValidators.addAll(IntelliJValidator.installedValidators);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2019 The Chromium 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 '../base/io.dart';
6+
import '../base/process_manager.dart';
7+
import '../base/version.dart';
8+
import '../doctor.dart';
9+
10+
/// A validator that checks for Clang and Make build dependencies
11+
class LinuxDoctorValidator extends DoctorValidator {
12+
LinuxDoctorValidator() : super('Linux toolchain - develop for Linux desktop');
13+
14+
/// The minimum version of clang supported.
15+
final Version minimumClangVersion = Version(3, 4, 0);
16+
17+
@override
18+
Future<ValidationResult> validate() async {
19+
ValidationType validationType = ValidationType.installed;
20+
final List<ValidationMessage> messages = <ValidationMessage>[];
21+
/// Check for a minimum version of Clang.
22+
final ProcessResult clangResult = await processManager.run(const <String>[
23+
'clang++',
24+
'--version',
25+
]);
26+
if (clangResult.exitCode != 0) {
27+
validationType = ValidationType.missing;
28+
messages.add(ValidationMessage.error('clang++ is not installed'));
29+
} else {
30+
final String firstLine = clangResult.stdout.split('\n').first.trim();
31+
final String versionString = RegExp(r'[0-9]+\.[0-9]+\.[0-9]+').firstMatch(firstLine).group(0);
32+
final Version version = Version.parse(versionString);
33+
if (version >= minimumClangVersion) {
34+
messages.add(ValidationMessage('clang++ $version'));
35+
} else {
36+
validationType = ValidationType.partial;
37+
messages.add(ValidationMessage.error('clang++ $version is below minimum version of $minimumClangVersion'));
38+
}
39+
}
40+
41+
/// Check for make.
42+
// TODO(jonahwilliams): tighten this check to include a version when we have
43+
// a better idea about what is supported.
44+
final ProcessResult makeResult = await processManager.run(const <String>[
45+
'make',
46+
'--version',
47+
]);
48+
if (makeResult.exitCode != 0) {
49+
validationType = ValidationType.missing;
50+
messages.add(ValidationMessage.error('make is not installed'));
51+
} else {
52+
final String firstLine = makeResult.stdout.split('\n').first.trim();
53+
messages.add(ValidationMessage(firstLine));
54+
}
55+
56+
return ValidationResult(validationType, messages);
57+
}
58+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2019 The Chromium 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:flutter_tools/src/doctor.dart';
6+
import 'package:flutter_tools/src/linux/linux_doctor.dart';
7+
import 'package:mockito/mockito.dart';
8+
import 'package:process/process.dart';
9+
10+
import '../src/common.dart';
11+
import '../src/context.dart';
12+
import '../src/mocks.dart';
13+
14+
void main() {
15+
group(LinuxDoctorValidator, () {
16+
ProcessManager processManager;
17+
LinuxDoctorValidator linuxDoctorValidator;
18+
19+
setUp(() {
20+
processManager = MockProcessManager();
21+
linuxDoctorValidator = LinuxDoctorValidator();
22+
});
23+
24+
testUsingContext('Returns full validation when clang++ and make are availibe', () async {
25+
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
26+
return FakeProcessResult(
27+
stdout: 'clang version 4.0.1-10 (tags/RELEASE_401/final)\njunk',
28+
exitCode: 0,
29+
);
30+
});
31+
when(processManager.run(<String>[
32+
'make',
33+
'--version',
34+
])).thenAnswer((_) async {
35+
return FakeProcessResult(
36+
stdout: 'GNU Make 4.1\njunk',
37+
exitCode: 0,
38+
);
39+
});
40+
41+
final ValidationResult result = await linuxDoctorValidator.validate();
42+
expect(result.type, ValidationType.installed);
43+
expect(result.messages, <ValidationMessage>[
44+
ValidationMessage('clang++ 4.0.1'),
45+
ValidationMessage('GNU Make 4.1'),
46+
]);
47+
}, overrides: <Type, Generator>{
48+
ProcessManager: () => processManager,
49+
});
50+
51+
testUsingContext('Returns partial validation when clang++ version is too old', () async {
52+
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
53+
return FakeProcessResult(
54+
stdout: 'clang version 2.0.1-10 (tags/RELEASE_401/final)\njunk',
55+
exitCode: 0,
56+
);
57+
});
58+
when(processManager.run(<String>[
59+
'make',
60+
'--version',
61+
])).thenAnswer((_) async {
62+
return FakeProcessResult(
63+
stdout: 'GNU Make 4.1\njunk',
64+
exitCode: 0,
65+
);
66+
});
67+
68+
final ValidationResult result = await linuxDoctorValidator.validate();
69+
expect(result.type, ValidationType.partial);
70+
expect(result.messages, <ValidationMessage>[
71+
ValidationMessage.error('clang++ 2.0.1 is below minimum version of 3.4.0'),
72+
ValidationMessage('GNU Make 4.1'),
73+
]);
74+
}, overrides: <Type, Generator>{
75+
ProcessManager: () => processManager,
76+
});
77+
78+
testUsingContext('Returns mising validation when make is not availible', () async {
79+
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
80+
return FakeProcessResult(
81+
stdout: 'clang version 4.0.1-10 (tags/RELEASE_401/final)\njunk',
82+
exitCode: 0,
83+
);
84+
});
85+
when(processManager.run(<String>[
86+
'make',
87+
'--version',
88+
])).thenAnswer((_) async {
89+
return FakeProcessResult(
90+
stdout: '',
91+
exitCode: 1,
92+
);
93+
});
94+
95+
final ValidationResult result = await linuxDoctorValidator.validate();
96+
expect(result.type, ValidationType.missing);
97+
expect(result.messages, <ValidationMessage>[
98+
ValidationMessage('clang++ 4.0.1'),
99+
ValidationMessage.error('make is not installed')
100+
]);
101+
}, overrides: <Type, Generator>{
102+
ProcessManager: () => processManager,
103+
});
104+
105+
testUsingContext('Returns mising validation when clang++ is not availible', () async {
106+
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
107+
return FakeProcessResult(
108+
stdout: '',
109+
exitCode: 1,
110+
);
111+
});
112+
when(processManager.run(<String>[
113+
'make',
114+
'--version',
115+
])).thenAnswer((_) async {
116+
return FakeProcessResult(
117+
stdout: 'GNU Make 4.1\njunk',
118+
exitCode: 0,
119+
);
120+
});
121+
122+
final ValidationResult result = await linuxDoctorValidator.validate();
123+
expect(result.type, ValidationType.missing);
124+
expect(result.messages, <ValidationMessage>[
125+
ValidationMessage.error('clang++ is not installed'),
126+
ValidationMessage('GNU Make 4.1'),
127+
]);
128+
}, overrides: <Type, Generator>{
129+
ProcessManager: () => processManager,
130+
});
131+
132+
133+
testUsingContext('Returns missing validation when clang and make are not availible', () async {
134+
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
135+
return FakeProcessResult(
136+
stdout: '',
137+
exitCode: 1,
138+
);
139+
});
140+
when(processManager.run(<String>[
141+
'make',
142+
'--version',
143+
])).thenAnswer((_) async {
144+
return FakeProcessResult(
145+
stdout: '',
146+
exitCode: 1,
147+
);
148+
});
149+
150+
final ValidationResult result = await linuxDoctorValidator.validate();
151+
expect(result.type, ValidationType.missing);
152+
}, overrides: <Type, Generator>{
153+
ProcessManager: () => processManager,
154+
});
155+
});
156+
}
157+
158+
class MockProcessManager extends Mock implements ProcessManager {}

packages/flutter_tools/test/src/mocks.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,3 +585,25 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler {
585585
return CompilerOutput(outputPath, 0, <Uri>[]);
586586
}
587587
}
588+
589+
/// A fake implementation of [ProcessResult].
590+
class FakeProcessResult implements ProcessResult {
591+
FakeProcessResult({
592+
this.exitCode = 0,
593+
this.pid = 1,
594+
this.stderr,
595+
this.stdout,
596+
});
597+
598+
@override
599+
final int exitCode;
600+
601+
@override
602+
final int pid;
603+
604+
@override
605+
final dynamic stderr;
606+
607+
@override
608+
final dynamic stdout;
609+
}

0 commit comments

Comments
 (0)