Unverified Commit 543186f1 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] quality pass on windows build (#55436)

parent d482163f
......@@ -11,13 +11,21 @@ Future<void> main(List<String> arguments) async {
final String targetPlatform = arguments[0];
final String buildMode = arguments[1].toLowerCase();
final String projectDirectory = Platform.environment['PROJECT_DIR'];
final bool verbose = Platform.environment['VERBOSE_SCRIPT_LOGGING'] != null;
final bool trackWidgetCreation = Platform.environment['TRACK_WIDGET_CREATION'] != null;
final String flutterTarget = Platform.environment['FLUTTER_TARGET'] ?? path.join('lib', 'main.dart');
final String dartDefines = Platform.environment['DART_DEFINES'];
final bool dartObfuscation = Platform.environment['DART_OBFUSCATION'] == 'true';
final String extraFrontEndOptions = Platform.environment['EXTRA_FRONT_END_OPTIONS'];
final String extraGenSnapshotOptions = Platform.environment['EXTRA_GEN_SNAPSHOT_OPTIONS'];
final String flutterEngine = Platform.environment['FLUTTER_ENGINE'];
final String localEngine = Platform.environment['LOCAL_ENGINE'];
final String flutterRoot = Platform.environment['FLUTTER_ROOT'];
final String flutterTarget = Platform.environment['FLUTTER_TARGET']
?? path.join('lib', 'main.dart');
final String localEngine = Platform.environment['LOCAL_ENGINE'];
final String projectDirectory = Platform.environment['PROJECT_DIR'];
final String splitDebugInfo = Platform.environment['SPLIT_DEBUG_INFO'];
final bool trackWidgetCreation = Platform.environment['TRACK_WIDGET_CREATION'] == 'true';
final bool treeShakeIcons = Platform.environment['TREE_SHAKE_ICONS'] == 'true';
final bool verbose = Platform.environment['VERBOSE_SCRIPT_LOGGING'] == 'true';
Directory.current = projectDirectory;
if (localEngine != null && !localEngine.contains(buildMode)) {
......@@ -50,12 +58,21 @@ or
if (flutterEngine != null) '--local-engine-src-path=$flutterEngine',
if (localEngine != null) '--local-engine=$localEngine',
'assemble',
if (trackWidgetCreation)
'-dTrackWidgetCreation=$trackWidgetCreation',
'--output=build',
'-dTargetPlatform=$targetPlatform',
'-dTrackWidgetCreation=$trackWidgetCreation',
'-dBuildMode=debug',
'-dTargetFile=$flutterTarget',
'--output=build',
'-dTreeShakeIcons="$treeShakeIcons"',
'-dDartObfuscation=$dartObfuscation',
if (splitDebugInfo != null)
'-dSplitDebugInfo=$splitDebugInfo',
if (dartDefines != null)
'--DartDefines=$dartDefines',
if (extraGenSnapshotOptions != null)
'--ExtraGenSnapshotOptions=$extraGenSnapshotOptions',
if (extraFrontEndOptions != null)
'-dExtraFrontEndOptions=$extraFrontEndOptions',
target,
],
);
......
......@@ -35,7 +35,7 @@ class BuildCommand extends FlutterCommand {
addSubcommand(BuildWebCommand(verboseHelp: verboseHelp));
addSubcommand(BuildMacosCommand(verboseHelp: verboseHelp));
addSubcommand(BuildLinuxCommand());
addSubcommand(BuildWindowsCommand());
addSubcommand(BuildWindowsCommand(verboseHelp: verboseHelp));
addSubcommand(BuildFuchsiaCommand(verboseHelp: verboseHelp));
}
......
......@@ -19,10 +19,17 @@ import 'build.dart';
/// A command to build a windows desktop target through a build shell script.
class BuildWindowsCommand extends BuildSubCommand {
BuildWindowsCommand() {
BuildWindowsCommand({ bool verboseHelp = false }) {
addTreeShakeIconsFlag();
addBuildModeFlags();
usesTargetOption();
addBuildModeFlags(verboseHelp: verboseHelp);
usesPubOption();
addSplitDebugInfoOption();
addDartObfuscationOption();
usesDartDefineOption();
usesExtraFrontendOptions();
addEnableExperimentation(hide: !verboseHelp);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
}
@override
......
......@@ -86,12 +86,20 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
// Run the script with a relative path to the project using the enclosing
// directory as the workingDirectory, to avoid hitting the limit on command
// lengths in batch scripts if the absolute path to the project is long.
result = await processUtils.stream(<String>[
buildScript,
vcvarsScript,
globals.fs.path.basename(solutionPath),
configuration,
], workingDirectory: globals.fs.path.dirname(solutionPath), trace: true);
result = await processUtils.stream(
<String>[
buildScript,
vcvarsScript,
globals.fs.path.basename(solutionPath),
configuration,
],
environment: <String, String>{
if (globals.logger.isVerbose)
'VERBOSE_SCRIPT_LOGGING': 'true'
},
workingDirectory: globals.fs.path.dirname(solutionPath),
trace: true,
);
} finally {
status.cancel();
}
......@@ -102,16 +110,32 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
}
/// Writes the generatedPropertySheetFile with the configuration for the given build.
void _writeGeneratedFlutterProperties(WindowsProject windowsProject, BuildInfo buildInfo, String target) {
void _writeGeneratedFlutterProperties(
WindowsProject windowsProject,
BuildInfo buildInfo,
String target,
) {
final Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': Cache.flutterRoot,
'FLUTTER_EPHEMERAL_DIR': windowsProject.ephemeralDirectory.path,
'PROJECT_DIR': windowsProject.project.directory.path,
'TRACK_WIDGET_CREATION': (buildInfo?.trackWidgetCreation == true).toString(),
if (buildInfo.trackWidgetCreation != null)
'TRACK_WIDGET_CREATION': buildInfo.trackWidgetCreation.toString(),
if (buildInfo.treeShakeIcons != null)
'TREE_SHAKE_ICONS': buildInfo.treeShakeIcons.toString(),
if (buildInfo.extraGenSnapshotOptions?.isNotEmpty ?? false)
'EXTRA_GEN_SNAPSHOT_OPTIONS': buildInfo.extraGenSnapshotOptions.join(','),
if (buildInfo.extraFrontEndOptions?.isNotEmpty ?? false)
'EXTRA_FRONT_END_OPTIONS': buildInfo.extraFrontEndOptions.join(','),
if (buildInfo.dartDefines?.isNotEmpty ?? false)
'DART_DEFINES': buildInfo.dartDefines.join(','),
if (buildInfo.dartObfuscation != null)
'DART_OBFUSCATION': buildInfo.dartObfuscation.toString(),
if (buildInfo.splitDebugInfoPath != null)
'SPLIT_DEBUG_INFO': buildInfo.splitDebugInfoPath,
if (target != null)
'FLUTTER_TARGET': target,
};
if (target != null) {
environment['FLUTTER_TARGET'] = target;
}
if (globals.artifacts is LocalEngineArtifacts) {
final LocalEngineArtifacts localEngineArtifacts = globals.artifacts as LocalEngineArtifacts;
final String engineOutPath = localEngineArtifacts.engineOutPath;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart';
......@@ -108,7 +109,7 @@ void main() {
setUpMockProjectFilesForBuild();
expect(createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
), throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
......@@ -125,7 +126,7 @@ void main() {
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
expect(createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
), throwsToolExit(message: 'No Windows desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
......@@ -142,7 +143,7 @@ void main() {
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
expect(createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
), throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => notWindowsPlatform,
......@@ -158,7 +159,7 @@ void main() {
setUpMockProjectFilesForBuild(templateVersion: 1);
expect(createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
), throwsToolExit(message: 'flutter create .'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
......@@ -174,7 +175,7 @@ void main() {
setUpMockProjectFilesForBuild(templateVersion: 999);
expect(createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
), throwsToolExit(message: 'Upgrade Flutter'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
......@@ -191,16 +192,19 @@ void main() {
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
when(mockProcessManager.start(<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
], workingDirectory: fileSystem.path.dirname(solutionPath))).thenAnswer((Invocation invocation) async {
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
],
environment: <String, String>{},
workingDirectory: fileSystem.path.dirname(solutionPath))
).thenAnswer((Invocation invocation) async {
return mockProcess;
});
await createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
);
expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
expect(testLogger.traceText, contains('STDOUT STUFF'));
......@@ -211,6 +215,39 @@ void main() {
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
});
testUsingContext('Windows verbose build sets VERBOSE_SCRIPT_LOGGING', () async {
final BuildWindowsCommand command = BuildWindowsCommand()
..visualStudioOverride = mockVisualStudio;
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
when(mockProcessManager.start(<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
],
environment: <String, String>{
'VERBOSE_SCRIPT_LOGGING': 'true',
},
workingDirectory: fileSystem.path.dirname(solutionPath))
).thenAnswer((Invocation invocation) async {
return mockProcess;
});
await createTestCommandRunner(command).run(
const <String>['windows', '--no-pub', '-v']
);
expect(testLogger.statusText, contains('STDOUT STUFF'));
expect(testLogger.traceText, isNot(contains('STDOUT STUFF')));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Platform: () => windowsPlatform,
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
});
testUsingContext('Windows build invokes msbuild and writes generated files', () async {
final BuildWindowsCommand command = BuildWindowsCommand()
..visualStudioOverride = mockVisualStudio;
......@@ -219,25 +256,48 @@ void main() {
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
when(mockProcessManager.start(<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
], workingDirectory: fileSystem.path.dirname(solutionPath))).thenAnswer((Invocation invocation) async {
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
],
environment: <String, String>{},
workingDirectory: fileSystem.path.dirname(solutionPath))
).thenAnswer((Invocation invocation) async {
return mockProcess;
});
await createTestCommandRunner(command).run(
const <String>['windows']
const <String>[
'windows',
'--no-pub',
'--track-widget-creation',
'--obfuscate',
'--tree-shake-icons',
'--enable-experiment=non-nullable',
r'--split-debug-info=C:\foo\',
'--dart-define=foo=a',
'--dart-define=bar=b',
r'--target=lib\main.dart',
]
);
// Spot-check important elements from the properties file.
final File propsFile = fileSystem.file(r'C:\windows\flutter\ephemeral\Generated.props');
expect(propsFile.existsSync(), true);
expect(propsFile, exists);
final xml.XmlDocument props = xml.parse(propsFile.readAsStringSync());
expect(props.findAllElements('PropertyGroup').first.getAttribute('Label'), 'UserMacros');
expect(props.findAllElements('ItemGroup').length, 1);
expect(props.findAllElements('FLUTTER_ROOT').first.text, flutterRoot);
expect(props.findAllElements('TRACK_WIDGET_CREATION').first.text, 'true');
expect(props.findAllElements('TREE_SHAKE_ICONS').first.text, 'true');
expect(props.findAllElements('EXTRA_GEN_SNAPSHOT_OPTIONS').first.text, '--enable-experiment=non-nullable');
expect(props.findAllElements('EXTRA_FRONT_END_OPTIONS').first.text, '--enable-experiment=non-nullable');
expect(props.findAllElements('DART_DEFINES').first.text, 'foo=a,bar=b');
expect(props.findAllElements('DART_OBFUSCATION').first.text, 'true');
expect(props.findAllElements('SPLIT_DEBUG_INFO').first.text, r'C:\foo\');
expect(props.findAllElements('FLUTTER_TARGET').first.text, r'lib\main.dart');
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
......@@ -252,17 +312,21 @@ void main() {
setUpMockProjectFilesForBuild();
when(mockVisualStudio.vcvarsPath).thenReturn(vcvarsPath);
when(mockProcessManager.start(<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
], workingDirectory: fileSystem.path.dirname(solutionPath))).thenAnswer((Invocation invocation) async {
return mockProcess;
});
when(mockProcessManager.start(
<String>[
fileSystem.path.join(flutterRoot, 'packages', 'flutter_tools', 'bin', 'vs_build.bat'),
vcvarsPath,
fileSystem.path.basename(solutionPath),
'Release',
],
environment: <String, String>{},
workingDirectory: fileSystem.path.dirname(solutionPath))).thenAnswer((Invocation invocation) async {
return mockProcess;
},
);
await createTestCommandRunner(command).run(
const <String>['windows']
const <String>['windows', '--no-pub']
);
expect(testLogger.statusText, contains('🚧'));
......
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