diff --git a/packages/flutter_tools/lib/src/commands/build_linux.dart b/packages/flutter_tools/lib/src/commands/build_linux.dart index b3e9b78061..81f096ac77 100644 --- a/packages/flutter_tools/lib/src/commands/build_linux.dart +++ b/packages/flutter_tools/lib/src/commands/build_linux.dart @@ -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; } diff --git a/packages/flutter_tools/lib/src/commands/build_macos.dart b/packages/flutter_tools/lib/src/commands/build_macos.dart index c966f3cf11..8d39a3a633 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos.dart @@ -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, diff --git a/packages/flutter_tools/lib/src/commands/build_windows.dart b/packages/flutter_tools/lib/src/commands/build_windows.dart index 7be232b781..3dd6ff705f 100644 --- a/packages/flutter_tools/lib/src/commands/build_windows.dart +++ b/packages/flutter_tools/lib/src/commands/build_windows.dart @@ -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; } diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 92e896a03a..c34a4f8e98 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -14,6 +14,12 @@ import '../reporting/reporting.dart'; /// Builds the Linux project through the Makefile. Future 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} diff --git a/packages/flutter_tools/lib/src/macos/build_macos.dart b/packages/flutter_tools/lib/src/macos/build_macos.dart index da6de5e990..d0c528a4fe 100644 --- a/packages/flutter_tools/lib/src/macos/build_macos.dart +++ b/packages/flutter_tools/lib/src/macos/build_macos.dart @@ -20,6 +20,12 @@ Future 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); diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 55e4b77a39..d4b3c50a2d 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -16,6 +16,13 @@ import 'visual_studio.dart'; /// Builds the Windows project using msbuild. Future 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 environment = { 'FLUTTER_ROOT': Cache.flutterRoot, 'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart index d2d93543d4..e6a7244a7d 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart @@ -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([ @@ -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 ['build', 'linux'] - ), throwsA(isInstanceOf())); + ), throwsToolExit(message: 'No Linux desktop project configured')); }, overrides: { Platform: () => linuxPlatform, FileSystem: () => MemoryFileSystem(), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart index 7f6d74fb0f..18ad8d42f3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart @@ -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 ['build', 'macos'] - ), throwsA(isInstanceOf())); + ), throwsToolExit(message: 'No macOS desktop project configured')); }, overrides: { Platform: () => macosPlatform, + FileSystem: () => MemoryFileSystem(), + ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), }); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 9a81864207..5b2f571b83 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -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 ['build', 'windows'] ), throwsA(isInstanceOf())); @@ -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 ['build', 'windows'] - ), throwsA(isInstanceOf())); + ), throwsToolExit(message: 'No Windows desktop project configured')); }, overrides: { 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 ['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([ 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([ 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([ r'C:\packages\flutter_tools\bin\vs_build.bat',