Unverified Commit b9932d55 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add linux doctor implementation (#34755)

parent ada95ef9
...@@ -113,7 +113,14 @@ task: ...@@ -113,7 +113,14 @@ task:
env: env:
CLOUDSDK_CORE_DISABLE_PROMPTS: 1 CLOUDSDK_CORE_DISABLE_PROMPTS: 1
GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[1c140257edc48f5578fa5a0e5038b84c8e53270c405efa5a8e35ea303a4e0d135853989f448f72136206de854d17fbec] GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[1c140257edc48f5578fa5a0e5038b84c8e53270c405efa5a8e35ea303a4e0d135853989f448f72136206de854d17fbec]
test_script: ./dev/bots/firebase_testlab.sh test_script:
- echo "$CIRRUS_CHANGE_MESSAGE" > /tmp/cirrus_change_message.txt
- echo "$CIRRUS_COMMIT_MESSAGE" > /tmp/cirrus_commit_message.txt
- export CIRRUS_CHANGE_MESSAGE=""
- export CIRRUS_COMMIT_MESSAGE=""
- ./dev/bots/firebase_testlab.sh
- export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt`
- export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt`
task: task:
use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == ''
......
...@@ -19,12 +19,14 @@ import 'base/user_messages.dart'; ...@@ -19,12 +19,14 @@ import 'base/user_messages.dart';
import 'base/utils.dart'; import 'base/utils.dart';
import 'base/version.dart'; import 'base/version.dart';
import 'cache.dart'; import 'cache.dart';
import 'desktop.dart';
import 'device.dart'; import 'device.dart';
import 'fuchsia/fuchsia_workflow.dart'; import 'fuchsia/fuchsia_workflow.dart';
import 'globals.dart'; import 'globals.dart';
import 'intellij/intellij.dart'; import 'intellij/intellij.dart';
import 'ios/ios_workflow.dart'; import 'ios/ios_workflow.dart';
import 'ios/plist_utils.dart'; import 'ios/plist_utils.dart';
import 'linux/linux_doctor.dart';
import 'linux/linux_workflow.dart'; import 'linux/linux_workflow.dart';
import 'macos/cocoapods_validator.dart'; import 'macos/cocoapods_validator.dart';
import 'macos/macos_workflow.dart'; import 'macos/macos_workflow.dart';
...@@ -69,12 +71,19 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { ...@@ -69,12 +71,19 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
if (iosWorkflow.appliesToHostPlatform) if (iosWorkflow.appliesToHostPlatform)
_validators.add(iosValidator); _validators.add(iosValidator);
if (windowsWorkflow.appliesToHostPlatform)
_validators.add(visualStudioValidator);
if (webWorkflow.appliesToHostPlatform) if (webWorkflow.appliesToHostPlatform)
_validators.add(const WebValidator()); _validators.add(const WebValidator());
// Add desktop doctors to workflow if the flag is enabled.
if (flutterDesktopEnabled) {
if (linuxWorkflow.appliesToHostPlatform) {
_validators.add(LinuxDoctorValidator());
}
if (windowsWorkflow.appliesToHostPlatform) {
_validators.add(visualStudioValidator);
}
}
final List<DoctorValidator> ideValidators = <DoctorValidator>[]; final List<DoctorValidator> ideValidators = <DoctorValidator>[];
ideValidators.addAll(AndroidStudioValidator.allValidators); ideValidators.addAll(AndroidStudioValidator.allValidators);
ideValidators.addAll(IntelliJValidator.installedValidators); ideValidators.addAll(IntelliJValidator.installedValidators);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../base/io.dart';
import '../base/process_manager.dart';
import '../base/version.dart';
import '../doctor.dart';
/// A validator that checks for Clang and Make build dependencies
class LinuxDoctorValidator extends DoctorValidator {
LinuxDoctorValidator() : super('Linux toolchain - develop for Linux desktop');
/// The minimum version of clang supported.
final Version minimumClangVersion = Version(3, 4, 0);
@override
Future<ValidationResult> validate() async {
ValidationType validationType = ValidationType.installed;
final List<ValidationMessage> messages = <ValidationMessage>[];
/// Check for a minimum version of Clang.
ProcessResult clangResult;
try {
clangResult = await processManager.run(const <String>[
'clang++',
'--version',
]);
} on ArgumentError {
// ignore error.
}
if (clangResult == null || clangResult.exitCode != 0) {
validationType = ValidationType.missing;
messages.add(ValidationMessage.error('clang++ is not installed'));
} else {
final String firstLine = clangResult.stdout.split('\n').first.trim();
final String versionString = RegExp(r'[0-9]+\.[0-9]+\.[0-9]+').firstMatch(firstLine).group(0);
final Version version = Version.parse(versionString);
if (version >= minimumClangVersion) {
messages.add(ValidationMessage('clang++ $version'));
} else {
validationType = ValidationType.partial;
messages.add(ValidationMessage.error('clang++ $version is below minimum version of $minimumClangVersion'));
}
}
/// Check for make.
// TODO(jonahwilliams): tighten this check to include a version when we have
// a better idea about what is supported.
ProcessResult makeResult;
try {
makeResult = await processManager.run(const <String>[
'make',
'--version',
]);
} on ArgumentError {
// ignore error.
}
if (makeResult == null || makeResult.exitCode != 0) {
validationType = ValidationType.missing;
messages.add(ValidationMessage.error('make is not installed'));
} else {
final String firstLine = makeResult.stdout.split('\n').first.trim();
messages.add(ValidationMessage(firstLine));
}
return ValidationResult(validationType, messages);
}
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/linux/linux_doctor.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
group(LinuxDoctorValidator, () {
ProcessManager processManager;
LinuxDoctorValidator linuxDoctorValidator;
setUp(() {
processManager = MockProcessManager();
linuxDoctorValidator = LinuxDoctorValidator();
});
testUsingContext('Returns full validation when clang++ and make are availibe', () async {
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'clang version 4.0.1-10 (tags/RELEASE_401/final)\njunk',
exitCode: 0,
);
});
when(processManager.run(<String>[
'make',
'--version',
])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'GNU Make 4.1\njunk',
exitCode: 0,
);
});
final ValidationResult result = await linuxDoctorValidator.validate();
expect(result.type, ValidationType.installed);
expect(result.messages, <ValidationMessage>[
ValidationMessage('clang++ 4.0.1'),
ValidationMessage('GNU Make 4.1'),
]);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
});
testUsingContext('Returns partial validation when clang++ version is too old', () async {
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'clang version 2.0.1-10 (tags/RELEASE_401/final)\njunk',
exitCode: 0,
);
});
when(processManager.run(<String>[
'make',
'--version',
])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'GNU Make 4.1\njunk',
exitCode: 0,
);
});
final ValidationResult result = await linuxDoctorValidator.validate();
expect(result.type, ValidationType.partial);
expect(result.messages, <ValidationMessage>[
ValidationMessage.error('clang++ 2.0.1 is below minimum version of 3.4.0'),
ValidationMessage('GNU Make 4.1'),
]);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
});
testUsingContext('Returns mising validation when make is not availible', () async {
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'clang version 4.0.1-10 (tags/RELEASE_401/final)\njunk',
exitCode: 0,
);
});
when(processManager.run(<String>[
'make',
'--version',
])).thenAnswer((_) async {
return FakeProcessResult(
stdout: '',
exitCode: 1,
);
});
final ValidationResult result = await linuxDoctorValidator.validate();
expect(result.type, ValidationType.missing);
expect(result.messages, <ValidationMessage>[
ValidationMessage('clang++ 4.0.1'),
ValidationMessage.error('make is not installed')
]);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
});
testUsingContext('Returns mising validation when clang++ is not availible', () async {
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
return FakeProcessResult(
stdout: '',
exitCode: 1,
);
});
when(processManager.run(<String>[
'make',
'--version',
])).thenAnswer((_) async {
return FakeProcessResult(
stdout: 'GNU Make 4.1\njunk',
exitCode: 0,
);
});
final ValidationResult result = await linuxDoctorValidator.validate();
expect(result.type, ValidationType.missing);
expect(result.messages, <ValidationMessage>[
ValidationMessage.error('clang++ is not installed'),
ValidationMessage('GNU Make 4.1'),
]);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
});
testUsingContext('Returns missing validation when clang and make are not availible', () async {
when(processManager.run(<String>['clang++', '--version'])).thenAnswer((_) async {
return FakeProcessResult(
stdout: '',
exitCode: 1,
);
});
when(processManager.run(<String>[
'make',
'--version',
])).thenAnswer((_) async {
return FakeProcessResult(
stdout: '',
exitCode: 1,
);
});
final ValidationResult result = await linuxDoctorValidator.validate();
expect(result.type, ValidationType.missing);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
});
});
}
class MockProcessManager extends Mock implements ProcessManager {}
...@@ -585,3 +585,25 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler { ...@@ -585,3 +585,25 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler {
return CompilerOutput(outputPath, 0, <Uri>[]); return CompilerOutput(outputPath, 0, <Uri>[]);
} }
} }
/// A fake implementation of [ProcessResult].
class FakeProcessResult implements ProcessResult {
FakeProcessResult({
this.exitCode = 0,
this.pid = 1,
this.stderr,
this.stdout,
});
@override
final int exitCode;
@override
final int pid;
@override
final dynamic stderr;
@override
final dynamic stdout;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment