Unverified Commit d8b6fa15 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] generate a synthetic flutter_gen package on pub get (#61261)

Allow configuring the flutter_manifest to support a synthetic package, this is done through flutter: generate: true.

When running pub get, insert a flutter_gen entry into the packages if it does not already exist. This points to .dart_tool/flutter_gen, which can be updated to contain the generated intl sources (But doesn't currently)

Adds an integration test that verifies this code can be run and imported when enabled.

Part of #60914
parent 3631adc9
...@@ -104,6 +104,7 @@ class BuildRunner extends CodeGenerator { ...@@ -104,6 +104,7 @@ class BuildRunner extends CodeGenerator {
directory: generatedDirectory.path, directory: generatedDirectory.path,
upgrade: false, upgrade: false,
checkLastModified: false, checkLastModified: false,
generateSyntheticPackage: false,
); );
if (!scriptIdFile.existsSync()) { if (!scriptIdFile.existsSync()) {
scriptIdFile.createSync(recursive: true); scriptIdFile.createSync(recursive: true);
......
...@@ -448,7 +448,8 @@ class _ResidentWebRunner extends ResidentWebRunner { ...@@ -448,7 +448,8 @@ class _ResidentWebRunner extends ResidentWebRunner {
// This will result in a NoSuchMethodError thrown by injected_handler.darts // This will result in a NoSuchMethodError thrown by injected_handler.darts
await pub.get( await pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: globals.fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools') directory: globals.fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools'),
generateSyntheticPackage: false,
); );
final ExpressionCompiler expressionCompiler = final ExpressionCompiler expressionCompiler =
......
...@@ -211,6 +211,7 @@ class BuildDaemonCreator { ...@@ -211,6 +211,7 @@ class BuildDaemonCreator {
await pub.get( await pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: globals.fs.file(buildScriptPackages).parent.path, directory: globals.fs.file(buildScriptPackages).parent.path,
generateSyntheticPackage: false,
); );
} }
final String flutterWebSdk = globals.artifacts.getArtifactPath(Artifact.flutterWebSdk); final String flutterWebSdk = globals.artifacts.getArtifactPath(Artifact.flutterWebSdk);
......
...@@ -543,6 +543,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ...@@ -543,6 +543,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
context: PubContext.create, context: PubContext.create,
directory: directory.path, directory: directory.path,
offline: boolArg('offline'), offline: boolArg('offline'),
generateSyntheticPackage: false,
); );
final FlutterProject project = FlutterProject.fromDirectory(directory); final FlutterProject project = FlutterProject.fromDirectory(directory);
await project.ensureReadyForPlatformSpecificTooling(checkProjects: false); await project.ensureReadyForPlatformSpecificTooling(checkProjects: false);
...@@ -562,6 +563,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ...@@ -562,6 +563,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
context: PubContext.createPackage, context: PubContext.createPackage,
directory: directory.path, directory: directory.path,
offline: boolArg('offline'), offline: boolArg('offline'),
generateSyntheticPackage: false,
); );
} }
return generatedCount; return generatedCount;
...@@ -606,6 +608,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ...@@ -606,6 +608,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
context: PubContext.createPlugin, context: PubContext.createPlugin,
directory: directory.path, directory: directory.path,
offline: boolArg('offline'), offline: boolArg('offline'),
generateSyntheticPackage: false,
); );
} }
...@@ -674,7 +677,12 @@ https://flutter.dev/docs/development/packages-and-plugins/developing-packages#pl ...@@ -674,7 +677,12 @@ https://flutter.dev/docs/development/packages-and-plugins/developing-packages#pl
} }
if (boolArg('pub')) { if (boolArg('pub')) {
await pub.get(context: PubContext.create, directory: directory.path, offline: boolArg('offline')); await pub.get(
context: PubContext.create,
directory: directory.path,
offline: boolArg('offline'),
generateSyntheticPackage: false,
);
await project.ensureReadyForPlatformSpecificTooling(checkProjects: pluginExampleApp); await project.ensureReadyForPlatformSpecificTooling(checkProjects: pluginExampleApp);
} }
if (templateContext['android'] == true) { if (templateContext['android'] == true) {
......
...@@ -88,7 +88,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -88,7 +88,7 @@ class PackagesGetCommand extends FlutterCommand {
return usageValues; return usageValues;
} }
Future<void> _runPubGet(String directory) async { Future<void> _runPubGet(String directory, FlutterProject flutterProject) async {
final Stopwatch pubGetTimer = Stopwatch()..start(); final Stopwatch pubGetTimer = Stopwatch()..start();
try { try {
await pub.get(context: PubContext.pubGet, await pub.get(context: PubContext.pubGet,
...@@ -96,6 +96,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -96,6 +96,7 @@ class PackagesGetCommand extends FlutterCommand {
upgrade: upgrade , upgrade: upgrade ,
offline: boolArg('offline'), offline: boolArg('offline'),
checkLastModified: false, checkLastModified: false,
generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage,
); );
pubGetTimer.stop(); pubGetTimer.stop();
globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success'); globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success');
...@@ -121,15 +122,15 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -121,15 +122,15 @@ class PackagesGetCommand extends FlutterCommand {
'${ workingDirectory ?? "current working directory" }.' '${ workingDirectory ?? "current working directory" }.'
); );
} }
await _runPubGet(target);
final FlutterProject rootProject = FlutterProject.fromPath(target); final FlutterProject rootProject = FlutterProject.fromPath(target);
await _runPubGet(target, rootProject);
await rootProject.ensureReadyForPlatformSpecificTooling(checkProjects: true); await rootProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
// Get/upgrade packages in example app as well // Get/upgrade packages in example app as well
if (rootProject.hasExampleApp) { if (rootProject.hasExampleApp) {
final FlutterProject exampleProject = rootProject.example; final FlutterProject exampleProject = rootProject.example;
await _runPubGet(exampleProject.directory.path); await _runPubGet(exampleProject.directory.path, exampleProject);
await exampleProject.ensureReadyForPlatformSpecificTooling(checkProjects: true); await exampleProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
} }
......
...@@ -163,15 +163,19 @@ class TestCommand extends FlutterCommand { ...@@ -163,15 +163,19 @@ class TestCommand extends FlutterCommand {
"called *_test.dart and must reside in the package's 'test' " "called *_test.dart and must reside in the package's 'test' "
'directory (or one of its subdirectories).'); 'directory (or one of its subdirectories).');
} }
final FlutterProject flutterProject = FlutterProject.current();
if (shouldRunPub) { if (shouldRunPub) {
await pub.get(context: PubContext.getVerifyContext(name), skipPubspecYamlCheck: true); await pub.get(
context: PubContext.getVerifyContext(name),
skipPubspecYamlCheck: true,
generateSyntheticPackage: flutterProject.manifest.generateSyntheticPackage,
);
} }
final bool buildTestAssets = boolArg('test-assets'); final bool buildTestAssets = boolArg('test-assets');
final List<String> names = stringsArg('name'); final List<String> names = stringsArg('name');
final List<String> plainNames = stringsArg('plain-name'); final List<String> plainNames = stringsArg('plain-name');
final String tags = stringArg('tags'); final String tags = stringArg('tags');
final String excludeTags = stringArg('exclude-tags'); final String excludeTags = stringArg('exclude-tags');
final FlutterProject flutterProject = FlutterProject.current();
if (buildTestAssets && flutterProject.manifest.assets.isNotEmpty) { if (buildTestAssets && flutterProject.manifest.assets.isNotEmpty) {
await _buildTestAsset(); await _buildTestAsset();
...@@ -222,7 +226,7 @@ class TestCommand extends FlutterCommand { ...@@ -222,7 +226,7 @@ class TestCommand extends FlutterCommand {
final bool machine = boolArg('machine'); final bool machine = boolArg('machine');
CoverageCollector collector; CoverageCollector collector;
if (boolArg('coverage') || boolArg('merge-coverage')) { if (boolArg('coverage') || boolArg('merge-coverage')) {
final String projectName = FlutterProject.current().manifest.appName; final String projectName = flutterProject.manifest.appName;
collector = CoverageCollector( collector = CoverageCollector(
verbose: !machine, verbose: !machine,
libraryPredicate: (String libraryName) => libraryName.contains(projectName), libraryPredicate: (String libraryName) => libraryName.contains(projectName),
......
...@@ -308,6 +308,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -308,6 +308,7 @@ class UpdatePackagesCommand extends FlutterCommand {
flutterRootOverride: upgrade flutterRootOverride: upgrade
? temporaryFlutterSdk.path ? temporaryFlutterSdk.path
: null, : null,
generateSyntheticPackage: false,
); );
// Cleanup the temporary SDK // Cleanup the temporary SDK
try { try {
...@@ -387,6 +388,7 @@ class UpdatePackagesCommand extends FlutterCommand { ...@@ -387,6 +388,7 @@ class UpdatePackagesCommand extends FlutterCommand {
directory: dir.path, directory: dir.path,
checkLastModified: false, checkLastModified: false,
offline: offline, offline: offline,
generateSyntheticPackage: false,
); );
count += 1; count += 1;
} }
......
...@@ -294,7 +294,13 @@ class UpgradeCommandRunner { ...@@ -294,7 +294,13 @@ class UpgradeCommandRunner {
final String projectRoot = findProjectRoot(); final String projectRoot = findProjectRoot();
if (projectRoot != null) { if (projectRoot != null) {
globals.printStatus(''); globals.printStatus('');
await pub.get(context: PubContext.pubUpgrade, directory: projectRoot, upgrade: true, checkLastModified: false); await pub.get(
context: PubContext.pubUpgrade,
directory: projectRoot,
upgrade: true,
checkLastModified: false,
generateSyntheticPackage: false,
);
} }
} }
......
...@@ -154,6 +154,7 @@ class VersionCommand extends FlutterCommand { ...@@ -154,6 +154,7 @@ class VersionCommand extends FlutterCommand {
directory: projectRoot, directory: projectRoot,
upgrade: true, upgrade: true,
checkLastModified: false, checkLastModified: false,
generateSyntheticPackage: false,
); );
} }
......
...@@ -207,6 +207,7 @@ Future<T> runInContext<T>( ...@@ -207,6 +207,7 @@ Future<T> runInContext<T>(
botDetector: globals.botDetector, botDetector: globals.botDetector,
platform: globals.platform, platform: globals.platform,
usage: globals.flutterUsage, usage: globals.flutterUsage,
toolStampFile: globals.cache.getStampFileFor('flutter_tools'),
), ),
ShutdownHooks: () => ShutdownHooks(logger: globals.logger), ShutdownHooks: () => ShutdownHooks(logger: globals.logger),
Stdio: () => Stdio(), Stdio: () => Stdio(),
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import '../base/bot_detector.dart'; import '../base/bot_detector.dart';
...@@ -16,6 +17,7 @@ import '../base/logger.dart'; ...@@ -16,6 +17,7 @@ import '../base/logger.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../cache.dart'; import '../cache.dart';
import '../dart/package_map.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
/// The [Pub] instance. /// The [Pub] instance.
...@@ -39,7 +41,7 @@ class PubContext { ...@@ -39,7 +41,7 @@ class PubContext {
for (final String item in _values) { for (final String item in _values) {
if (!_validContext.hasMatch(item)) { if (!_validContext.hasMatch(item)) {
throw ArgumentError.value( throw ArgumentError.value(
_values, 'value', 'Must match RegExp ${_validContext.pattern}'); _values, 'value', 'Must match RegExp ${_validContext.pattern}');
} }
} }
} }
...@@ -80,6 +82,7 @@ abstract class Pub { ...@@ -80,6 +82,7 @@ abstract class Pub {
@required Platform platform, @required Platform platform,
@required BotDetector botDetector, @required BotDetector botDetector,
@required Usage usage, @required Usage usage,
File toolStampFile,
}) = _DefaultPub; }) = _DefaultPub;
/// Runs `pub get`. /// Runs `pub get`.
...@@ -94,6 +97,7 @@ abstract class Pub { ...@@ -94,6 +97,7 @@ abstract class Pub {
bool offline = false, bool offline = false,
bool checkLastModified = true, bool checkLastModified = true,
bool skipPubspecYamlCheck = false, bool skipPubspecYamlCheck = false,
bool generateSyntheticPackage = false,
String flutterRootOverride, String flutterRootOverride,
}); });
...@@ -139,7 +143,9 @@ class _DefaultPub implements Pub { ...@@ -139,7 +143,9 @@ class _DefaultPub implements Pub {
@required Platform platform, @required Platform platform,
@required BotDetector botDetector, @required BotDetector botDetector,
@required Usage usage, @required Usage usage,
}) : _fileSystem = fileSystem, File toolStampFile,
}) : _toolStampFile = toolStampFile,
_fileSystem = fileSystem,
_logger = logger, _logger = logger,
_platform = platform, _platform = platform,
_botDetector = botDetector, _botDetector = botDetector,
...@@ -155,6 +161,7 @@ class _DefaultPub implements Pub { ...@@ -155,6 +161,7 @@ class _DefaultPub implements Pub {
final Platform _platform; final Platform _platform;
final BotDetector _botDetector; final BotDetector _botDetector;
final Usage _usage; final Usage _usage;
final File _toolStampFile;
@override @override
Future<void> get({ Future<void> get({
...@@ -165,6 +172,7 @@ class _DefaultPub implements Pub { ...@@ -165,6 +172,7 @@ class _DefaultPub implements Pub {
bool offline = false, bool offline = false,
bool checkLastModified = true, bool checkLastModified = true,
bool skipPubspecYamlCheck = false, bool skipPubspecYamlCheck = false,
bool generateSyntheticPackage = false,
String flutterRootOverride, String flutterRootOverride,
}) async { }) async {
directory ??= _fileSystem.currentDirectory.path; directory ??= _fileSystem.currentDirectory.path;
...@@ -173,6 +181,7 @@ class _DefaultPub implements Pub { ...@@ -173,6 +181,7 @@ class _DefaultPub implements Pub {
_fileSystem.path.join(directory, 'pubspec.yaml')); _fileSystem.path.join(directory, 'pubspec.yaml'));
final File packageConfigFile = _fileSystem.file( final File packageConfigFile = _fileSystem.file(
_fileSystem.path.join(directory, '.dart_tool', 'package_config.json')); _fileSystem.path.join(directory, '.dart_tool', 'package_config.json'));
final Directory generatedDirectory = _fileSystem.directory(_fileSystem.path.join(directory, '.dart_tool', 'flutter_gen'));
if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) { if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) {
if (!skipIfAbsent) { if (!skipIfAbsent) {
...@@ -242,6 +251,10 @@ class _DefaultPub implements Pub { ...@@ -242,6 +251,10 @@ class _DefaultPub implements Pub {
'The time now is: $now' 'The time now is: $now'
); );
} }
// Insert references to synthetic flutter package.
if (generateSyntheticPackage) {
await _updatePackageConfig(packageConfigFile, generatedDirectory);
}
} }
@override @override
...@@ -387,6 +400,12 @@ class _DefaultPub implements Pub { ...@@ -387,6 +400,12 @@ class _DefaultPub implements Pub {
if (pubSpecYaml.lastModifiedSync().isAfter(dotPackagesLastModified)) { if (pubSpecYaml.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true; return true;
} }
if (_toolStampFile != null &&
_toolStampFile.existsSync() &&
_toolStampFile.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true;
}
return false; return false;
} }
...@@ -439,4 +458,27 @@ class _DefaultPub implements Pub { ...@@ -439,4 +458,27 @@ class _DefaultPub implements Pub {
} }
return environment; return environment;
} }
/// Insert the flutter_gen synthetic package into the package configuration file if
/// there is an l10n.yaml.
Future<void> _updatePackageConfig(File packageConfigFile, Directory generatedDirectory) async {
if (!packageConfigFile.existsSync()) {
return;
}
final PackageConfig packageConfig = await loadPackageConfigWithLogging(packageConfigFile, logger: _logger);
final Package flutterGen = Package('flutter_gen', generatedDirectory.uri, languageVersion: LanguageVersion(2, 8));
if (packageConfig.packages.any((Package package) => package.name == 'flutter_gen')) {
return;
}
final PackageConfig newPackageConfig = PackageConfig(
<Package>[
...packageConfig.packages,
flutterGen,
],
);
// There is no current API for saving a package_config without hitting the real filesystem.
if (packageConfigFile.fileSystem is LocalFileSystem) {
await savePackageConfig(newPackageConfig, packageConfigFile.parent.parent);
}
}
} }
...@@ -279,6 +279,26 @@ class FlutterManifest { ...@@ -279,6 +279,26 @@ class FlutterManifest {
} }
return fonts; return fonts;
} }
/// Whether a synthetic flutter_gen package should be generated.
///
/// This can be provided to the [Pub] interface to inject a new entry
/// into the package_config.json file which points to `.dart_tool/flutter_gen`.
///
/// This allows generated source code to be imported using a package
/// alias.
bool get generateSyntheticPackage => _generateSyntheticPackage ??= _computeGenerateSyntheticPackage();
bool _generateSyntheticPackage;
bool _computeGenerateSyntheticPackage() {
if (!_flutterDescriptor.containsKey('generate')) {
return false;
}
final Object value = _flutterDescriptor['generate'];
if (value is! bool) {
return false;
}
return value as bool;
}
} }
class Font { class Font {
...@@ -438,6 +458,8 @@ void _validateFlutter(YamlMap yaml, List<String> errors) { ...@@ -438,6 +458,8 @@ void _validateFlutter(YamlMap yaml, List<String> errors) {
final List<String> pluginErrors = Plugin.validatePluginYaml(kvp.value as YamlMap); final List<String> pluginErrors = Plugin.validatePluginYaml(kvp.value as YamlMap);
errors.addAll(pluginErrors); errors.addAll(pluginErrors);
break; break;
case 'generate':
break;
default: default:
errors.add('Unexpected child "${kvp.key}" found under "flutter".'); errors.add('Unexpected child "${kvp.key}" found under "flutter".');
break; break;
......
...@@ -845,10 +845,13 @@ abstract class FlutterCommand extends Command<void> { ...@@ -845,10 +845,13 @@ abstract class FlutterCommand extends Command<void> {
await validateCommand(); await validateCommand();
if (shouldRunPub) { if (shouldRunPub) {
await pub.get(context: PubContext.getVerifyContext(name)); final FlutterProject project = FlutterProject.current();
await pub.get(
context: PubContext.getVerifyContext(name),
generateSyntheticPackage: project.manifest.generateSyntheticPackage,
);
// All done updating dependencies. Release the cache lock. // All done updating dependencies. Release the cache lock.
Cache.releaseLock(); Cache.releaseLock();
final FlutterProject project = FlutterProject.current();
await project.ensureReadyForPlatformSpecificTooling(checkProjects: true); await project.ensureReadyForPlatformSpecificTooling(checkProjects: true);
} else { } else {
Cache.releaseLock(); Cache.releaseLock();
......
...@@ -301,5 +301,6 @@ Future<void> _ensurePackageDependencies(String packagePath) async { ...@@ -301,5 +301,6 @@ Future<void> _ensurePackageDependencies(String packagePath) async {
await pub.get( await pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: packagePath, directory: packagePath,
generateSyntheticPackage: false,
); );
} }
...@@ -77,7 +77,11 @@ void main() { ...@@ -77,7 +77,11 @@ void main() {
botDetector: globals.botDetector, botDetector: globals.botDetector,
usage: globals.flutterUsage, usage: globals.flutterUsage,
); );
await pub.get(context: PubContext.flutterTests, directory: tempDir.path); await pub.get(
context: PubContext.flutterTests,
directory: tempDir.path,
generateSyntheticPackage: false,
);
server = AnalysisServer( server = AnalysisServer(
globals.artifacts.getArtifactPath(Artifact.engineDartSdkPath), globals.artifacts.getArtifactPath(Artifact.engineDartSdkPath),
...@@ -111,8 +115,13 @@ void main() { ...@@ -111,8 +115,13 @@ void main() {
platform: const LocalPlatform(), platform: const LocalPlatform(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
botDetector: globals.botDetector, botDetector: globals.botDetector,
toolStampFile: globals.fs.file('test'),
);
await pub.get(
context: PubContext.flutterTests,
directory: tempDir.path,
generateSyntheticPackage: false,
); );
await pub.get(context: PubContext.flutterTests, directory: tempDir.path);
server = AnalysisServer( server = AnalysisServer(
globals.artifacts.getArtifactPath(Artifact.engineDartSdkPath), globals.artifacts.getArtifactPath(Artifact.engineDartSdkPath),
......
...@@ -197,10 +197,10 @@ void main() { ...@@ -197,10 +197,10 @@ void main() {
}); });
testWithoutContext('analytics sent on success', () async { testWithoutContext('analytics sent on success', () async {
MockDirectory.findCache = true; final FileSystem fileSystem = MemoryFileSystem.test();
final MockUsage usage = MockUsage(); final MockUsage usage = MockUsage();
final Pub pub = Pub( final Pub pub = Pub(
fileSystem: MockFileSystem(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: MockProcessManager(0), processManager: MockProcessManager(0),
botDetector: const BotDetectorAlwaysNo(), botDetector: const BotDetectorAlwaysNo(),
...@@ -211,8 +211,16 @@ void main() { ...@@ -211,8 +211,16 @@ void main() {
} }
), ),
); );
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.dart_tool/package_config.json')
..createSync(recursive: true)
..writeAsStringSync('{"configVersion": 2,"packages": []}');
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(
context: PubContext.flutterTests,
generateSyntheticPackage: true,
checkLastModified: false,
);
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1); verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
}); });
...@@ -242,10 +250,10 @@ void main() { ...@@ -242,10 +250,10 @@ void main() {
}); });
testWithoutContext('analytics sent on failed version solve', () async { testWithoutContext('analytics sent on failed version solve', () async {
MockDirectory.findCache = true;
final MockUsage usage = MockUsage(); final MockUsage usage = MockUsage();
final FileSystem fileSystem = MemoryFileSystem.test();
final Pub pub = Pub( final Pub pub = Pub(
fileSystem: MockFileSystem(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: MockProcessManager( processManager: MockProcessManager(
1, 1,
...@@ -259,6 +267,7 @@ void main() { ...@@ -259,6 +267,7 @@ void main() {
usage: usage, usage: usage,
botDetector: const BotDetectorAlwaysNo(), botDetector: const BotDetectorAlwaysNo(),
); );
fileSystem.file('pubspec.yaml').writeAsStringSync('name: foo');
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
......
...@@ -82,6 +82,60 @@ flutter: ...@@ -82,6 +82,60 @@ flutter:
expect(flutterManifest.usesMaterialDesign, true); expect(flutterManifest.usesMaterialDesign, true);
}); });
testWithoutContext('FlutterManifest knows if generate is provided', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: true
''';
final BufferLogger logger = BufferLogger.test();
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest.generateSyntheticPackage, true);
});
testWithoutContext('FlutterManifest can parse invalid generate key', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: "invalid"
''';
final BufferLogger logger = BufferLogger.test();
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest.generateSyntheticPackage, false);
});
testWithoutContext('FlutterManifest knows if generate is disabled', () async {
const String manifest = '''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
generate: false
''';
final BufferLogger logger = BufferLogger.test();
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest.generateSyntheticPackage, false);
});
testWithoutContext('FlutterManifest has two assets', () async { testWithoutContext('FlutterManifest has two assets', () async {
const String manifest = ''' const String manifest = '''
name: test name: test
......
...@@ -297,6 +297,7 @@ void main() { ...@@ -297,6 +297,7 @@ void main() {
verify(pub.get( verify(pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: anyNamed('directory'), directory: anyNamed('directory'),
generateSyntheticPackage: false,
)).called(1); )).called(1);
expect(bufferLogger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/')); expect(bufferLogger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/'));
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import '../src/common.dart';
import 'test_data/basic_project.dart';
import 'test_driver.dart';
import 'test_utils.dart';
void main() {
Directory tempDir;
final BasicProjectWithFlutterGen project = BasicProjectWithFlutterGen();
FlutterRunTestDriver flutter;
setUp(() async {
tempDir = createResolvedTempDirectorySync('run_test.');
await project.setUpIn(tempDir);
flutter = FlutterRunTestDriver(tempDir);
});
tearDown(() async {
await flutter.stop();
tryToDelete(tempDir);
});
test('can correctly reference flutter generated code.', () async {
await flutter.run();
});
}
...@@ -53,7 +53,11 @@ class BasicProject extends Project { ...@@ -53,7 +53,11 @@ class BasicProject extends Project {
int get topLevelFunctionBreakpointLine => lineContaining(main, '// TOP LEVEL BREAKPOINT'); int get topLevelFunctionBreakpointLine => lineContaining(main, '// TOP LEVEL BREAKPOINT');
} }
class BasicProjectWithUnaryMain extends Project { class BasicProjectWithFlutterGen extends Project {
@override
final String generatedFile = '''
String x = "a";
''';
@override @override
final String pubspec = ''' final String pubspec = '''
...@@ -64,21 +68,42 @@ class BasicProjectWithUnaryMain extends Project { ...@@ -64,21 +68,42 @@ class BasicProjectWithUnaryMain extends Project {
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter:
generate: true
'''; ''';
@override @override
final String main = r''' final String main = r'''
import 'dart:async'; import 'dart:async';
import 'package:flutter_gen/flutter_gen.dart';
import 'package:flutter/material.dart'; void main() {}
''';
}
class BasicProjectWithUnaryMain extends Project {
@override
final String pubspec = '''
name: test
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
''';
@override
final String main = r'''
import 'dart:async';
import 'package:flutter/material.dart';
Future<void> main(List<String> args) async { Future<void> main(List<String> args) async {
while (true) { while (true) {
runApp(new MyApp()); runApp(new MyApp());
await Future.delayed(const Duration(milliseconds: 50)); await Future.delayed(const Duration(milliseconds: 50));
} }
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -89,7 +114,6 @@ class BasicProjectWithUnaryMain extends Project { ...@@ -89,7 +114,6 @@ class BasicProjectWithUnaryMain extends Project {
); );
} }
} }
topLevelFunction() { topLevelFunction() {
print("topLevelFunction"); // TOP LEVEL BREAKPOINT print("topLevelFunction"); // TOP LEVEL BREAKPOINT
} }
......
...@@ -27,6 +27,7 @@ abstract class Project { ...@@ -27,6 +27,7 @@ abstract class Project {
String get pubspec; String get pubspec;
String get main; String get main;
String get test => null; String get test => null;
String get generatedFile => null;
Uri get mainDart => Uri.parse('package:test/main.dart'); Uri get mainDart => Uri.parse('package:test/main.dart');
...@@ -39,6 +40,9 @@ abstract class Project { ...@@ -39,6 +40,9 @@ abstract class Project {
if (test != null) { if (test != null) {
writeFile(globals.fs.path.join(dir.path, 'test', 'test.dart'), test); writeFile(globals.fs.path.join(dir.path, 'test', 'test.dart'), test);
} }
if (generatedFile != null) {
writeFile(globals.fs.path.join(dir.path, '.dart_tool', 'flutter_gen', 'flutter_gen.dart'), generatedFile);
}
writeFile(globals.fs.path.join(dir.path, 'web', 'index.html'), _kDefaultHtml); writeFile(globals.fs.path.join(dir.path, 'web', 'index.html'), _kDefaultHtml);
writePackages(dir.path); writePackages(dir.path);
await getPackages(dir.path); await getPackages(dir.path);
......
...@@ -30,6 +30,7 @@ class ThrowingPub implements Pub { ...@@ -30,6 +30,7 @@ class ThrowingPub implements Pub {
bool offline = false, bool offline = false,
bool checkLastModified = true, bool checkLastModified = true,
bool skipPubspecYamlCheck = false, bool skipPubspecYamlCheck = false,
bool generateSyntheticPackage = false,
String flutterRootOverride, String flutterRootOverride,
}) { }) {
throw UnsupportedError('Attempted to invoke pub during test.'); throw UnsupportedError('Attempted to invoke pub during test.');
......
...@@ -95,6 +95,7 @@ void main() { ...@@ -95,6 +95,7 @@ void main() {
when(pub.get( when(pub.get(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: anyNamed('directory'), directory: anyNamed('directory'),
generateSyntheticPackage: false,
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
// Create valid package entry. // Create valid package entry.
packagesFile.writeAsStringSync('flutter_template_images:file:///flutter_template_images'); packagesFile.writeAsStringSync('flutter_template_images:file:///flutter_template_images');
......
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