[gen_l10n] Create pubspec.yaml in ".dart_tool/flutter_gen" if it does not already exist (#68206)
* Generate pubspec.yaml for synthetic package if it did not exist prior
diff --git a/packages/flutter_tools/lib/src/build_system/targets/localizations.dart b/packages/flutter_tools/lib/src/build_system/targets/localizations.dart
index 156ec73..1a03fec 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/localizations.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/localizations.dart
@@ -119,7 +119,6 @@
logger: environment.logger,
fileSystem: environment.fileSystem,
);
-
generateLocalizations(
logger: environment.logger,
options: options,
diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart
index a961b16..79dc52e 100644
--- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart
+++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart
@@ -13,12 +13,15 @@
import 'gen_l10n_types.dart';
import 'localizations_utils.dart';
-/// The default path used when the `useSyntheticPackage` setting is set to true
+/// The path for the synthetic package.
+final String defaultSyntheticPackagePath = globals.fs.path.join('.dart_tool', 'flutter_gen');
+
+/// The default path used when the `_useSyntheticPackage` setting is set to true
/// in [LocalizationsGenerator].
///
/// See [LocalizationsGenerator.initialize] for where and how it is used by the
/// localizations tool.
-final String defaultSyntheticPackagePath = globals.fs.path.join('.dart_tool', 'flutter_gen', 'gen_l10n');
+final String syntheticL10nPackagePath = globals.fs.path.join(defaultSyntheticPackagePath, 'gen_l10n');
List<String> generateMethodParameters(Message message) {
assert(message.placeholders.isNotEmpty);
@@ -405,6 +408,7 @@
Iterable<Message> _allMessages;
AppResourceBundleCollection _allBundles;
LocaleInfo _templateArbLocale;
+ bool _useSyntheticPackage = true;
/// The directory that contains the project's arb files, as well as the
/// header file, if specified.
@@ -538,12 +542,10 @@
bool useSyntheticPackage = true,
String projectPathString,
}) {
+ _useSyntheticPackage = useSyntheticPackage;
setProjectDir(projectPathString);
setInputDirectory(inputPathString);
- setOutputDirectory(
- outputPathString: outputPathString ?? inputPathString,
- useSyntheticPackage: useSyntheticPackage,
- );
+ setOutputDirectory(outputPathString ?? inputPathString);
setTemplateArbFile(templateArbFileName);
setBaseOutputFile(outputFileString);
setPreferredSupportedLocales(preferredSupportedLocale);
@@ -614,15 +616,14 @@
/// Sets the reference [Directory] for [outputDirectory].
@visibleForTesting
- void setOutputDirectory({
+ void setOutputDirectory(
String outputPathString,
- bool useSyntheticPackage = true,
- }) {
- if (useSyntheticPackage) {
+ ) {
+ if (_useSyntheticPackage) {
outputDirectory = _fs.directory(
projectDirectory != null
- ? _getAbsoluteProjectPath(defaultSyntheticPackagePath)
- : defaultSyntheticPackagePath
+ ? _getAbsoluteProjectPath(syntheticL10nPackagePath)
+ : syntheticL10nPackagePath
);
} else {
if (outputPathString == null) {
@@ -1004,11 +1005,20 @@
// First, generate the string contents of all necessary files.
_generateCode();
+ // A pubspec.yaml file is required when using a synthetic package. If it does not
+ // exist, create a blank one.
+ if (_useSyntheticPackage) {
+ final Directory syntheticPackageDirectory = _fs.directory(defaultSyntheticPackagePath);
+ syntheticPackageDirectory.createSync(recursive: true);
+ final File flutterGenPubspec = syntheticPackageDirectory.childFile('pubspec.yaml');
+ if (!flutterGenPubspec.existsSync()) {
+ flutterGenPubspec.writeAsStringSync(emptyPubspecTemplate);
+ }
+ }
+
// Since all validity checks have passed up to this point,
// write the contents into the directory.
- if (!outputDirectory.existsSync()) {
- outputDirectory.createSync(recursive: true);
- }
+ outputDirectory.createSync(recursive: true);
// Ensure that the created directory has read/write permissions.
final FileStat fileStat = outputDirectory.statSync();
diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n_templates.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n_templates.dart
index 1302fbf..14f731e 100644
--- a/packages/flutter_tools/lib/src/localizations/gen_l10n_templates.dart
+++ b/packages/flutter_tools/lib/src/localizations/gen_l10n_templates.dart
@@ -2,6 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+const String emptyPubspecTemplate = '''# Generated by the flutter tool
+name: synthetic_package
+description: The Flutter application's synthetic package.
+''';
+
const String fileTemplate = '''
@(header)
import 'dart:async';
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 5d5bc66..ac8c6ac 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -877,7 +877,6 @@
processManager: globals.processManager,
projectDir: globals.fs.currentDirectory,
);
- globals.logger.printTrace('Starting incremental build...');
_lastBuild = await globals.buildSystem.buildIncremental(
const GenerateLocalizationsTarget(),
_environment,
diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart
index 125b458..7002897 100644
--- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart
+++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart
@@ -6,6 +6,7 @@
import 'dart:io';
import 'package:file/memory.dart';
+import 'package:yaml/yaml.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
@@ -19,7 +20,8 @@
export 'package:test_core/test_core.dart' hide TypeMatcher, isInstanceOf, test; // Defines a 'package:test' shim.
final String defaultL10nPathString = globals.fs.path.join('lib', 'l10n');
-final String syntheticPackagePath = globals.fs.path.join('.dart_tool', 'flutter_gen', 'gen_l10n');
+final String syntheticPackagePath = globals.fs.path.join('.dart_tool', 'flutter_gen');
+final String syntheticL10nPackagePath = globals.fs.path.join(syntheticPackagePath, 'gen_l10n');
const String defaultTemplateArbFileName = 'app_en.arb';
const String defaultOutputFileString = 'output-localization-file.dart';
const String defaultClassNameString = 'AppLocalizations';
@@ -109,10 +111,8 @@
_standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try {
- generator.setOutputDirectory(
- outputPathString: null,
- useSyntheticPackage: false,
- );
+ generator.initialize(useSyntheticPackage: false);
+ generator.setOutputDirectory(null);
} on L10nException catch (e) {
expect(e.message, contains('cannot be null'));
return;
@@ -302,7 +302,7 @@
generator = LocalizationsGenerator(fs);
try {
generator.setInputDirectory(defaultL10nPathString);
- generator.setOutputDirectory();
+ generator.setOutputDirectory(null);
generator.setTemplateArbFile(defaultTemplateArbFileName);
generator.setBaseOutputFile(defaultOutputFileString);
} on L10nException catch (e) {
@@ -433,7 +433,7 @@
fail('Generating output should not fail: \n${e.message}');
}
- final Directory outputDirectory = fs.directory(syntheticPackagePath);
+ final Directory outputDirectory = fs.directory(syntheticL10nPackagePath);
expect(outputDirectory.childFile('output-localization-file.dart').existsSync(), isTrue);
expect(outputDirectory.childFile('output-localization-file_en.dart').existsSync(), isTrue);
expect(outputDirectory.childFile('output-localization-file_es.dart').existsSync(), isTrue);
@@ -624,7 +624,7 @@
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
- inputsAndOutputsListPath: syntheticPackagePath,
+ inputsAndOutputsListPath: syntheticL10nPackagePath,
)
..loadResources()
..writeOutputFiles();
@@ -633,7 +633,7 @@
}
final File inputsAndOutputsList = fs.file(
- fs.path.join(syntheticPackagePath, 'gen_l10n_inputs_and_outputs.json'),
+ fs.path.join(syntheticL10nPackagePath, 'gen_l10n_inputs_and_outputs.json'),
);
expect(inputsAndOutputsList.existsSync(), isTrue);
@@ -645,9 +645,9 @@
expect(jsonResult.containsKey('outputs'), isTrue);
final List<dynamic> outputList = jsonResult['outputs'] as List<dynamic>;
- expect(outputList, contains(fs.path.absolute(syntheticPackagePath, 'output-localization-file.dart')));
- expect(outputList, contains(fs.path.absolute(syntheticPackagePath, 'output-localization-file_en.dart')));
- expect(outputList, contains(fs.path.absolute(syntheticPackagePath, 'output-localization-file_es.dart')));
+ expect(outputList, contains(fs.path.absolute(syntheticL10nPackagePath, 'output-localization-file.dart')));
+ expect(outputList, contains(fs.path.absolute(syntheticL10nPackagePath, 'output-localization-file_en.dart')));
+ expect(outputList, contains(fs.path.absolute(syntheticL10nPackagePath, 'output-localization-file_es.dart')));
});
test('setting both a headerString and a headerFile should fail', () {
@@ -1095,11 +1095,11 @@
fail('Generating output files should not fail: $e');
}
- expect(fs.isFileSync(fs.path.join(syntheticPackagePath, 'output-localization-file_en.dart')), true);
- expect(fs.isFileSync(fs.path.join(syntheticPackagePath, 'output-localization-file_en_US.dart')), false);
+ expect(fs.isFileSync(fs.path.join(syntheticL10nPackagePath, 'output-localization-file_en.dart')), true);
+ expect(fs.isFileSync(fs.path.join(syntheticL10nPackagePath, 'output-localization-file_en_US.dart')), false);
final String englishLocalizationsFile = fs.file(
- fs.path.join(syntheticPackagePath, 'output-localization-file_en.dart')
+ fs.path.join(syntheticL10nPackagePath, 'output-localization-file_en.dart')
).readAsStringSync();
expect(englishLocalizationsFile, contains('class AppLocalizationsEnCa extends AppLocalizationsEn'));
expect(englishLocalizationsFile, contains('class AppLocalizationsEn extends AppLocalizations'));
@@ -1129,7 +1129,7 @@
}
final String localizationsFile = fs.file(
- fs.path.join(syntheticPackagePath, defaultOutputFileString),
+ fs.path.join(syntheticL10nPackagePath, defaultOutputFileString),
).readAsStringSync();
expect(localizationsFile, contains(
'''
@@ -1159,7 +1159,7 @@
}
final String localizationsFile = fs.file(
- fs.path.join(syntheticPackagePath, defaultOutputFileString),
+ fs.path.join(syntheticL10nPackagePath, defaultOutputFileString),
).readAsStringSync();
expect(localizationsFile, contains(
'''
@@ -1586,4 +1586,62 @@
});
});
});
+
+ test('should generate a valid pubspec.yaml file when using synthetic package if it does not already exist', () {
+ _standardFlutterDirectoryL10nSetup(fs);
+ LocalizationsGenerator generator;
+ try {
+ generator = LocalizationsGenerator(fs);
+ generator
+ ..initialize(
+ inputPathString: defaultL10nPathString,
+ templateArbFileName: defaultTemplateArbFileName,
+ outputFileString: defaultOutputFileString,
+ classNameString: defaultClassNameString,
+ )
+ ..loadResources()
+ ..writeOutputFiles();
+ } on L10nException catch (e) {
+ fail('Generating output should not fail: \n${e.message}');
+ }
+
+ final Directory outputDirectory = fs.directory(syntheticPackagePath);
+ final File pubspecFile = outputDirectory.childFile('pubspec.yaml');
+ expect(pubspecFile.existsSync(), isTrue);
+
+ final YamlNode yamlNode = loadYamlNode(pubspecFile.readAsStringSync());
+ expect(yamlNode, isA<YamlMap>());
+
+ final YamlMap yamlMap = yamlNode as YamlMap;
+ final String pubspecName = yamlMap['name'] as String;
+ final String pubspecDescription = yamlMap['description'] as String;
+ expect(pubspecName, 'synthetic_package');
+ expect(pubspecDescription, "The Flutter application's synthetic package.");
+ });
+
+ test('should not overwrite existing pubspec.yaml file when using synthetic package', () {
+ _standardFlutterDirectoryL10nSetup(fs);
+ final File pubspecFile = fs.file(fs.path.join(syntheticPackagePath, 'pubspec.yaml'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('abcd');
+
+ LocalizationsGenerator generator;
+ try {
+ generator = LocalizationsGenerator(fs);
+ generator
+ ..initialize(
+ inputPathString: defaultL10nPathString,
+ templateArbFileName: defaultTemplateArbFileName,
+ outputFileString: defaultOutputFileString,
+ classNameString: defaultClassNameString,
+ )
+ ..loadResources()
+ ..writeOutputFiles();
+ } on L10nException catch (e) {
+ fail('Generating output should not fail: \n${e.message}');
+ }
+
+ // The original pubspec file should not be overwritten.
+ expect(pubspecFile.readAsStringSync(), 'abcd');
+ });
}