Unverified Commit 58d6c425 authored by stuartmorgan's avatar stuartmorgan Committed by GitHub

Check for desktop project files before building (#48350)

Moves the checks that projects have been configured for desktop to a lower level, where they will cover more codepaths (e.g., 'run'), and improves them to check for native build projects, rather than just directories, to catch cases where the directory exists (e.g., due to accidental creation of generated files).

Also adds links to the error messages pointing to instructions on adding desktop support to a project.

Fixes #47145
parent 67c843f7
......@@ -46,9 +46,6 @@ class BuildLinuxCommand extends BuildSubCommand {
if (!globals.platform.isLinux) {
throwToolExit('"build linux" only supported on Linux hosts.');
}
if (!flutterProject.linux.existsSync()) {
throwToolExit('No Linux desktop project configured.');
}
await buildLinux(flutterProject.linux, buildInfo, target: targetFile);
return null;
}
......
......@@ -46,9 +46,6 @@ class BuildMacosCommand extends BuildSubCommand {
if (!globals.platform.isMacOS) {
throwToolExit('"build macos" only supported on macOS hosts.');
}
if (!flutterProject.macos.existsSync()) {
throwToolExit('No macOS desktop project configured.');
}
await buildMacOS(
flutterProject: flutterProject,
buildInfo: buildInfo,
......
......@@ -46,9 +46,6 @@ class BuildWindowsCommand extends BuildSubCommand {
if (!globals.platform.isWindows) {
throwToolExit('"build windows" only supported on Windows hosts.');
}
if (!flutterProject.windows.existsSync()) {
throwToolExit('No Windows desktop project configured.');
}
await buildWindows(flutterProject.windows, buildInfo, target: targetFile);
return null;
}
......
......@@ -14,6 +14,12 @@ import '../reporting/reporting.dart';
/// Builds the Linux project through the Makefile.
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
if (!linuxProject.makeFile.existsSync()) {
throwToolExit('No Linux desktop project configured. See '
'https://github.com/flutter/flutter/wiki/Desktop-shells#create '
'to learn about adding Linux support to a project.');
}
final StringBuffer buffer = StringBuffer('''
# Generated code do not commit.
export FLUTTER_ROOT=${Cache.flutterRoot}
......
......@@ -20,6 +20,12 @@ Future<void> buildMacOS({
BuildInfo buildInfo,
String targetOverride,
}) async {
if (!flutterProject.macos.xcodeWorkspace.existsSync()) {
throwToolExit('No macOS desktop project configured. '
'See https://flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-project '
'to learn about adding macOS support to a project.');
}
final Directory flutterBuildDir = globals.fs.directory(getMacOSBuildDirectory());
if (!flutterBuildDir.existsSync()) {
flutterBuildDir.createSync(recursive: true);
......
......@@ -16,6 +16,13 @@ import 'visual_studio.dart';
/// Builds the Windows project using msbuild.
Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {String target}) async {
if (!windowsProject.solutionFile.existsSync()) {
throwToolExit(
'No Windows desktop project configured. '
'See https://github.com/flutter/flutter/wiki/Desktop-shells#create '
'to learn about adding Windows support to a project.');
}
final Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': Cache.flutterRoot,
'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path,
......
......@@ -55,14 +55,19 @@ void main() {
when(notLinuxPlatform.isWindows).thenReturn(false);
});
// Creates the mock files necessary to run a build.
void setUpMockProjectFilesForBuild() {
globals.fs.file('linux/build.sh').createSync(recursive: true);
// Creates the mock files necessary to look like a Flutter project.
void setUpMockCoreProjectFiles() {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
}
// Creates the mock files necessary to run a build.
void setUpMockProjectFilesForBuild() {
globals.fs.file(globals.fs.path.join('linux', 'Makefile')).createSync(recursive: true);
setUpMockCoreProjectFiles();
}
// Sets up mock expectation for running 'make'.
void expectMakeInvocationWithMode(String buildModeName) {
when(mockProcessManager.start(<String>[
......@@ -78,9 +83,10 @@ void main() {
testUsingContext('Linux build fails when there is no linux project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockCoreProjectFiles();
expect(createTestCommandRunner(command).run(
const <String>['build', 'linux']
), throwsA(isInstanceOf<ToolExit>()));
), throwsToolExit(message: 'No Linux desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
......
......@@ -67,14 +67,19 @@ void main() {
when(notMacosPlatform.isWindows).thenReturn(false);
});
// Sets up the minimal mock project files necessary for macOS builds to succeed.
void createMinimalMockProjectFiles() {
globals.fs.directory('macos').createSync();
// Sets up the minimal mock project files necessary to look like a Flutter project.
void createCoreMockProjectFiles() {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
}
// Sets up the minimal mock project files necessary for macOS builds to succeed.
void createMinimalMockProjectFiles() {
globals.fs.directory(globals.fs.path.join('macos', 'Runner.xcworkspace')).createSync(recursive: true);
createCoreMockProjectFiles();
}
// Mocks the process manager to handle an xcodebuild call to build the app
// in the given configuration.
void setUpMockXcodeBuildHandler(String configuration) {
......@@ -102,11 +107,14 @@ void main() {
testUsingContext('macOS build fails when there is no macos project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createCoreMockProjectFiles();
expect(createTestCommandRunner(command).run(
const <String>['build', 'macos']
), throwsA(isInstanceOf<ToolExit>()));
), throwsToolExit(message: 'No macOS desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => macosPlatform,
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
......
......@@ -58,10 +58,23 @@ void main() {
when(notWindowsPlatform.isWindows).thenReturn(false);
});
// Creates the mock files necessary to look like a Flutter project.
void setUpMockCoreProjectFiles() {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
}
// Creates the mock files necessary to run a build.
void setUpMockProjectFilesForBuild() {
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockCoreProjectFiles();
}
testUsingContext('Windows build fails when there is no vcvars64.bat', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockProjectFilesForBuild();
expect(createTestCommandRunner(command).run(
const <String>['build', 'windows']
), throwsA(isInstanceOf<ToolExit>()));
......@@ -76,10 +89,11 @@ void main() {
testUsingContext('Windows build fails when there is no windows project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockCoreProjectFiles();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
expect(createTestCommandRunner(command).run(
const <String>['build', 'windows']
), throwsA(isInstanceOf<ToolExit>()));
), throwsToolExit(message: 'No Windows desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
FileSystem: () => MemoryFileSystem(style: FileSystemStyle.windows),
......@@ -91,11 +105,8 @@ void main() {
testUsingContext('Windows build fails on non windows platform', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
expect(createTestCommandRunner(command).run(
const <String>['build', 'windows']
......@@ -111,11 +122,8 @@ void main() {
testUsingContext('Windows build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
when(mockProcessManager.start(<String>[
r'C:\packages\flutter_tools\bin\vs_build.bat',
......@@ -142,11 +150,8 @@ void main() {
testUsingContext('Windows build invokes msbuild and writes generated files', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
when(mockProcessManager.start(<String>[
r'C:\packages\flutter_tools\bin\vs_build.bat',
......@@ -179,11 +184,8 @@ void main() {
testUsingContext('Release build prints an under-construction warning', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file(solutionPath).createSync(recursive: true);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
when(mockProcessManager.start(<String>[
r'C:\packages\flutter_tools\bin\vs_build.bat',
......
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