diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart index eed033fd..80f3a013 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_ios_command.dart @@ -92,9 +92,9 @@ If this option is not provided, the version number will be determined from the p ) ..addFlag( 'debug-linker', - negatable: false, + defaultsTo: true, help: 'Collects linker diagnostic information to help troubleshoot low ' - 'link percentages.', + 'link percentages. File is saved to build/$_linkDebugInfoFileName.', ); } @@ -378,8 +378,9 @@ Please re-run the release command for this version or create a new release.'''); '🟢 Track: ${lightCyan.wrap('Production')}', if (percentLinked != null) '''🔗 Running ${lightCyan.wrap('${percentLinked.toStringAsFixed(1)}%')} on CPU''', - if (results['debug-linker'] == true) - '''🔍 Debug Info: ${lightCyan.wrap(_debugInfoOutpath)}''', + if (results['debug-linker'] == true && + (percentLinked != null && percentLinked < minLinkPercentage)) + '''🔍 Debug Info: ${lightCyan.wrap(_debugInfoOutputPath)}''', ]; logger.info( @@ -453,9 +454,10 @@ ${summary.join('\n')} 'out.vmcode', ); - String get _debugInfoOutpath => p.join( + static const _linkDebugInfoFileName = 'linker_diagnostic.zip'; + String get _debugInfoOutputPath => p.join( _buildDirectory, - 'linker_diagnostic.zip', + _linkDebugInfoFileName, ); String _readVersionFromPlist() { @@ -527,7 +529,8 @@ ${summary.join('\n')} required File releaseArtifact, }) async { final patch = File(_aotOutputPath); - final dumpDebugInfo = results['debug-linker'] == true; + final dumpDebugInfo = results['debug-linker'] == true && + (await aotTools.isLinkDebugInfoSupported()); if (!patch.existsSync()) { logger.err('Unable to find patch AOT file at ${patch.path}'); @@ -571,7 +574,7 @@ ${summary.join('\n')} debugInfoZip.copySync( p.join( 'build', - _debugInfoOutpath, + _debugInfoOutputPath, ), ); } diff --git a/packages/shorebird_cli/lib/src/executables/aot_tools.dart b/packages/shorebird_cli/lib/src/executables/aot_tools.dart index cd910e66..5e3ea368 100644 --- a/packages/shorebird_cli/lib/src/executables/aot_tools.dart +++ b/packages/shorebird_cli/lib/src/executables/aot_tools.dart @@ -131,6 +131,11 @@ class AotTools { return tryParseVersion(version) ?? noVersion; } + Future isLinkDebugInfoSupported() async { + final result = await _exec(['link', '--help']); + return result.stdout.toString().contains('dump-debug-info'); + } + /// Generate a link vmcode file from two AOT snapshots. Future link({ required String base, diff --git a/packages/shorebird_cli/pubspec.lock b/packages/shorebird_cli/pubspec.lock index 2caf0ec8..4268e17d 100644 --- a/packages/shorebird_cli/pubspec.lock +++ b/packages/shorebird_cli/pubspec.lock @@ -762,10 +762,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "7475cb4dd713d57b6f7464c0e13f06da0d535d8b2067e188962a59bac2cf280b" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.2" watcher: dependency: transitive description: diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart index 23121b54..86303d9f 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_ios_command_test.dart @@ -18,6 +18,7 @@ import 'package:shorebird_cli/src/deployment_track.dart'; import 'package:shorebird_cli/src/doctor.dart'; import 'package:shorebird_cli/src/engine_config.dart'; import 'package:shorebird_cli/src/executables/aot_tools.dart'; +import 'package:shorebird_cli/src/executables/executables.dart'; import 'package:shorebird_cli/src/executables/xcodebuild.dart'; import 'package:shorebird_cli/src/logger.dart'; import 'package:shorebird_cli/src/os/operating_system_interface.dart'; @@ -529,6 +530,8 @@ flutter: command = runWithOverrides( () => PatchIosCommand(archiveDiffer: archiveDiffer), )..testArgResults = argResults; + + when(aotTools.isLinkDebugInfoSupported).thenAnswer((_) async => true); }); test('supports alpha alias', () { @@ -1321,6 +1324,67 @@ Please re-run the release command for this version or create a new release.'''), ).called(1); }, ); + + test( + 'prints the file location when linking is less than the minimum', + () async { + const notEnoughLinkPercentage = 60.0; + when( + () => aotTools.link( + base: any(named: 'base'), + patch: any(named: 'patch'), + analyzeSnapshot: any(named: 'analyzeSnapshot'), + genSnapshot: any(named: 'genSnapshot'), + kernel: any(named: 'kernel'), + workingDirectory: any(named: 'workingDirectory'), + outputPath: any(named: 'outputPath'), + dumpDebugInfoPath: any(named: 'dumpDebugInfoPath'), + ), + ).thenAnswer( + (_) async => notEnoughLinkPercentage, + ); + when(() => argResults['debug-linker']).thenReturn(true); + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); + expect(exitCode, ExitCode.success.code); + + final captured = verify(() => logger.info(captureAny())).captured + as List; + final contains = captured.whereType().any( + (element) => element.contains('Debug Info'), + ); + expect(contains, isTrue); + }, + ); + + group("when aot-tools don't support debugging the link command", () { + test( + "don't debug even when the flag is true", + () async { + when(() => argResults['debug-linker']).thenReturn(true); + when(aotTools.isLinkDebugInfoSupported).thenAnswer( + (_) async => false, + ); + + setUpProjectRoot(); + setUpProjectRootArtifacts(); + final exitCode = await runWithOverrides(command.run); + expect(exitCode, ExitCode.success.code); + verify( + () => aotTools.link( + base: any(named: 'base'), + patch: any(named: 'patch'), + analyzeSnapshot: any(named: 'analyzeSnapshot'), + genSnapshot: any(named: 'genSnapshot'), + kernel: any(named: 'kernel'), + workingDirectory: any(named: 'workingDirectory'), + outputPath: any(named: 'outputPath'), + ), + ).called(1); + }, + ); + }); }); }); diff --git a/packages/shorebird_cli/test/src/executables/aot_tools_test.dart b/packages/shorebird_cli/test/src/executables/aot_tools_test.dart index cdb343f3..b35ac3fa 100644 --- a/packages/shorebird_cli/test/src/executables/aot_tools_test.dart +++ b/packages/shorebird_cli/test/src/executables/aot_tools_test.dart @@ -474,6 +474,92 @@ void main() { ).called(1); }); }); + + group('isLinkDebugInfoSupported', () { + test('returns true when the argument is present in the help', () async { + final result = MockShorebirdProcessResult(); + when(() => result.exitCode).thenReturn(ExitCode.success.code); + when(() => result.stdout).thenReturn(''' +Link two aot snapshots. + +Usage: aot_tools link [arguments] +-h, --help Print this usage information. + --base (mandatory) Path to the base snapshot to link against. + --patch (mandatory) Path to the patch snapshot to link. + --analyze-snapshot (mandatory) Path to analyze_snapshot binary. + --gen-snapshot (mandatory) Path to gen_snapshot binary. + --kernel (mandatory) Path to the patch kernel (.dill) file. + --output (mandatory) Path to the output vmcode file. + --enable-asserts Whether to enable asserts. + --linker-overrides Path to the linker overrides json file. + --dump-debug-info When specified, debug information will be generated and written to the provided path. + --reporter Set how to print link results. + + [json] Prints the results in json format. + [pretty] (default) Prints the results in a human readable format. + + --redirect-to Redirect output to a file. + +Run "aot_tools help" to see global options. +'''); + + when( + () => process.run( + any(), + any(), + workingDirectory: any(named: 'workingDirectory'), + ), + ).thenAnswer((_) async => result); + + await expectLater( + runWithOverrides(() => aotTools.isLinkDebugInfoSupported()), + completion(isTrue), + ); + }); + + test( + 'returns false when the argument is not present in the help', + () async { + final result = MockShorebirdProcessResult(); + when(() => result.exitCode).thenReturn(ExitCode.success.code); + when(() => result.stdout).thenReturn(''' +Link two aot snapshots. + +Usage: aot_tools link [arguments] +-h, --help Print this usage information. + --base (mandatory) Path to the base snapshot to link against. + --patch (mandatory) Path to the patch snapshot to link. + --analyze-snapshot (mandatory) Path to analyze_snapshot binary. + --gen-snapshot (mandatory) Path to gen_snapshot binary. + --kernel (mandatory) Path to the patch kernel (.dill) file. + --output (mandatory) Path to the output vmcode file. + --enable-asserts Whether to enable asserts. + --linker-overrides Path to the linker overrides json file. + --reporter Set how to print link results. + + [json] Prints the results in json format. + [pretty] (default) Prints the results in a human readable format. + + --redirect-to Redirect output to a file. + +Run "aot_tools help" to see global options. +'''); + + when( + () => process.run( + any(), + any(), + workingDirectory: any(named: 'workingDirectory'), + ), + ).thenAnswer((_) async => result); + + await expectLater( + runWithOverrides(() => aotTools.isLinkDebugInfoSupported()), + completion(isFalse), + ); + }, + ); + }); }); group('isGeneratePatchDiffBaseSupported', () {