diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index 2a62dfccf31..2800d6253b8 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -147,6 +147,8 @@ class GenerateLocalizationsCommand extends FlutterCommand { 'generated as a synthetic package or at a specified directory in ' 'the Flutter project.\n' '\n' + 'DEPRECATED: https://flutter.dev/to/flutter-gen-deprecation.\n' + '\n' 'This flag is set to true by default.\n' '\n' 'When synthetic-package is set to false, it will generate the ' diff --git a/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart b/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart index 655b365fc6c..b5c0e6f1339 100644 --- a/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart +++ b/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart @@ -15,10 +15,10 @@ Future generateLocalizationsSyntheticPackage({ required BuildSystem buildSystem, required BuildTargets buildTargets, }) async { - final FileSystem fileSystem = environment.fileSystem; final File l10nYamlFile = fileSystem.file( - fileSystem.path.join(environment.projectDir.path, 'l10n.yaml')); + fileSystem.path.join(environment.projectDir.path, 'l10n.yaml'), + ); // If pubspec.yaml has generate:true and if l10n.yaml exists in the // root project directory, check to see if a synthetic package should @@ -30,7 +30,7 @@ Future generateLocalizationsSyntheticPackage({ final YamlNode yamlNode = loadYamlNode(l10nYamlFile.readAsStringSync()); if (yamlNode.value != null && yamlNode is! YamlMap) { throwToolExit( - 'Expected ${l10nYamlFile.path} to contain a map, instead was $yamlNode' + 'Expected ${l10nYamlFile.path} to contain a map, instead was $yamlNode', ); } @@ -41,8 +41,7 @@ Future generateLocalizationsSyntheticPackage({ final Object? value = yamlMap['synthetic-package']; if (value is! bool && value != null) { throwToolExit( - 'Expected "synthetic-package" to have a bool value, ' - 'instead was "$value"' + 'Expected "synthetic-package" to have a bool value, instead was "$value"', ); } @@ -52,8 +51,30 @@ Future generateLocalizationsSyntheticPackage({ if (isSyntheticL10nPackage == false) { return; } + } else if (!environment.useImplicitPubspecResolution) { + // --no-implicit-pubspec-resolution was passed, and synthetic-packages: true was not. + return; } + if (!environment.useImplicitPubspecResolution) { + throwToolExit( + 'Cannot generate a synthetic package when --no-implicit-pubspec-resolution is passed.\n' + '\n' + 'Synthetic package output (package:flutter_gen) is deprecated: ' + 'https://flutter.dev/to/flutter-gen-deprecation. If you are seeing this ' + 'message either you have provided --no-implicit-pubspec-resolution, or ' + 'it is the default value (see flutter --verbose --help).', + ); + } + + // Log a warning: synthetic-package: true (or implicit true) is deprecated. + environment.logger.printWarning( + 'Synthetic package output (package:flutter_gen) is deprecated: ' + 'https://flutter.dev/to/flutter-gen-deprecation. In a future release, ' + 'synthetic-package will default to `false` and will later be removed ' + 'entirely.', + ); + final BuildResult result = await buildSystem.build( buildTargets.generateLocalizationsTarget, environment, diff --git a/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart b/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart index fe65d0f2655..f29ca480209 100644 --- a/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart @@ -267,4 +267,185 @@ void main() { throwsToolExit(message: 'to have a bool value, instead was "nonBoolValue"'), ); }); + + testWithoutContext('synthetic-package: true (implicit) logs a deprecation warning', () async { + // Project directory setup for gen_l10n logic. + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + + // Add generate:true to pubspec.yaml. + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + final String content = pubspecFile.readAsStringSync().replaceFirst( + '\nflutter:\n', + '\nflutter:\n generate: true\n', + ); + pubspecFile.writeAsStringSync(content); + + // Create a blank l10n.yaml file. + fileSystem.file('l10n.yaml').writeAsStringSync(''); + + final BufferLogger mockBufferLogger = BufferLogger.test(); + final Environment environment = Environment.test( + fileSystem.currentDirectory, + fileSystem: fileSystem, + logger: mockBufferLogger, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), + ); + final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); + + await generateLocalizationsSyntheticPackage( + environment: environment, + buildSystem: buildSystem, + buildTargets: const BuildTargetsImpl(), + ); + + expect( + mockBufferLogger.warningText, + contains('https://flutter.dev/to/flutter-gen-deprecation'), + ); + }); + + testWithoutContext('synthetic-package: true (explicit) logs a deprecation warning', () async { + // Project directory setup for gen_l10n logic. + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + + // Add generate:true to pubspec.yaml. + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + final String content = pubspecFile.readAsStringSync().replaceFirst( + '\nflutter:\n', + '\nflutter:\n generate: true\n', + ); + pubspecFile.writeAsStringSync(content); + fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: true'); + + final BufferLogger mockBufferLogger = BufferLogger.test(); + final Environment environment = Environment.test( + fileSystem.currentDirectory, + fileSystem: fileSystem, + logger: mockBufferLogger, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), + ); + final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); + + await generateLocalizationsSyntheticPackage( + environment: environment, + buildSystem: buildSystem, + buildTargets: const BuildTargetsImpl(), + ); + + expect( + mockBufferLogger.warningText, + contains('https://flutter.dev/to/flutter-gen-deprecation'), + ); + }); + + testWithoutContext('synthetic-package: false has no deprecation warning', () async { + // Project directory setup for gen_l10n logic + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + + // Add generate:true to pubspec.yaml. + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + final String content = pubspecFile.readAsStringSync().replaceFirst( + '\nflutter:\n', + '\nflutter:\n generate: true\n', + ); + pubspecFile.writeAsStringSync(content); + fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: false'); + + final BufferLogger mockBufferLogger = BufferLogger.test(); + final Environment environment = Environment.test( + fileSystem.currentDirectory, + fileSystem: fileSystem, + logger: mockBufferLogger, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), + ); + final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); + + await generateLocalizationsSyntheticPackage( + environment: environment, + buildSystem: buildSystem, + buildTargets: const BuildTargetsImpl(), + ); + + expect( + mockBufferLogger.warningText, + isNot(contains('https://flutter.dev/to/flutter-gen-deprecation')), + ); + }); + + testWithoutContext('synthetic-package: true with --no-implicit-pubspec-resolution is an error', () async { + // Project directory setup for gen_l10n logic + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + + // Add generate:true to pubspec.yaml. + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + final String content = pubspecFile.readAsStringSync().replaceFirst( + '\nflutter:\n', + '\nflutter:\n generate: true\n', + ); + pubspecFile.writeAsStringSync(content); + + // Create an l10n.yaml file + fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: true'); + + final BufferLogger mockBufferLogger = BufferLogger.test(); + final Environment environment = Environment.test( + fileSystem.currentDirectory, + fileSystem: fileSystem, + logger: mockBufferLogger, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), + useImplicitPubspecResolution: false, + ); + // Will throw if build is called. + final TestBuildSystem buildSystem = TestBuildSystem.all(null); + + await expectLater( + () => generateLocalizationsSyntheticPackage( + environment: environment, + buildSystem: buildSystem, + buildTargets: const NoOpBuildTargets(), + ), + throwsToolExit(message: 'Cannot generate a synthetic package when --no-implicit-pubspec-resolution is passed'), + ); + }); + + testWithoutContext('synthetic-package defaults to false if --no-implicit-pubspec-resolution is passed', () async { + // Project directory setup for gen_l10n logic + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + + // Add generate:true to pubspec.yaml. + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + final String content = pubspecFile.readAsStringSync().replaceFirst( + '\nflutter:\n', + '\nflutter:\n generate: true\n', + ); + pubspecFile.writeAsStringSync(content); + + // Create an l10n.yaml file + fileSystem.file('l10n.yaml').writeAsStringSync(''); + + final BufferLogger mockBufferLogger = BufferLogger.test(); + final Environment environment = Environment.test( + fileSystem.currentDirectory, + fileSystem: fileSystem, + logger: mockBufferLogger, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), + useImplicitPubspecResolution: false, + ); + // Will throw if build is called. + final TestBuildSystem buildSystem = TestBuildSystem.all(null); + + await expectLater( + () => generateLocalizationsSyntheticPackage( + environment: environment, + buildSystem: buildSystem, + buildTargets: const NoOpBuildTargets(), + ), + returnsNormally, + ); + }); }