mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Migrate create command to null safety (#104484)
This commit is contained in:
parent
b5adbee145
commit
09987dc00a
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import '../android/gradle_utils.dart' as gradle;
|
||||
import '../base/common.dart';
|
||||
import '../base/context.dart';
|
||||
@ -32,8 +30,8 @@ const String kPlatformHelp =
|
||||
|
||||
class CreateCommand extends CreateBase {
|
||||
CreateCommand({
|
||||
bool verboseHelp = false,
|
||||
}) : super(verboseHelp: verboseHelp) {
|
||||
super.verboseHelp = false,
|
||||
}) {
|
||||
addPlatformsOptions(customHelp: kPlatformHelp);
|
||||
argParser.addOption(
|
||||
'template',
|
||||
@ -57,7 +55,6 @@ class CreateCommand extends CreateBase {
|
||||
flutterProjectTypeToString(FlutterProjectType.module): 'Generate a project to add a Flutter module to an '
|
||||
'existing Android or iOS application.',
|
||||
},
|
||||
defaultsTo: null,
|
||||
);
|
||||
argParser.addOption(
|
||||
'sample',
|
||||
@ -66,7 +63,6 @@ class CreateCommand extends CreateBase {
|
||||
'"--template=app". The value should be the sample ID of the desired sample from the API '
|
||||
'documentation website (http://docs.flutter.dev/). An example can be found at: '
|
||||
'https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html',
|
||||
defaultsTo: null,
|
||||
valueHelp: 'id',
|
||||
);
|
||||
argParser.addOption(
|
||||
@ -88,7 +84,7 @@ class CreateCommand extends CreateBase {
|
||||
String get category => FlutterCommandCategory.project;
|
||||
|
||||
@override
|
||||
String get invocation => '${runner.executableName} $name <output directory>';
|
||||
String get invocation => '${runner?.executableName} $name <output directory>';
|
||||
|
||||
@override
|
||||
Future<CustomDimensions> get usageValues async {
|
||||
@ -100,8 +96,7 @@ class CreateCommand extends CreateBase {
|
||||
}
|
||||
|
||||
// Lazy-initialize the net utilities with values from the context.
|
||||
Net _cachedNet;
|
||||
Net get _net => _cachedNet ??= Net(
|
||||
late final Net _net = Net(
|
||||
httpClientFactory: context.get<HttpClientFactory>(),
|
||||
logger: globals.logger,
|
||||
platform: globals.platform,
|
||||
@ -112,7 +107,7 @@ class CreateCommand extends CreateBase {
|
||||
? 'api.flutter.dev'
|
||||
: 'master-api.flutter.dev';
|
||||
|
||||
Future<String> _fetchSampleFromServer(String sampleId) async {
|
||||
Future<String?> _fetchSampleFromServer(String sampleId) async {
|
||||
// Sanity check the sampleId
|
||||
if (sampleId.contains(RegExp(r'[^-\w\.]'))) {
|
||||
throwToolExit('Sample ID "$sampleId" contains invalid characters. Check the ID in the '
|
||||
@ -120,7 +115,7 @@ class CreateCommand extends CreateBase {
|
||||
}
|
||||
|
||||
final Uri snippetsUri = Uri.https(_snippetsHost, 'snippets/$sampleId.dart');
|
||||
final List<int> data = await _net.fetchUrl(snippetsUri);
|
||||
final List<int>? data = await _net.fetchUrl(snippetsUri);
|
||||
if (data == null || data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
@ -128,9 +123,9 @@ class CreateCommand extends CreateBase {
|
||||
}
|
||||
|
||||
/// Fetches the samples index file from the Flutter docs website.
|
||||
Future<String> _fetchSamplesIndexFromServer() async {
|
||||
Future<String?> _fetchSamplesIndexFromServer() async {
|
||||
final Uri snippetsUri = Uri.https(_snippetsHost, 'snippets/index.json');
|
||||
final List<int> data = await _net.fetchUrl(snippetsUri, maxAttempts: 2);
|
||||
final List<int>? data = await _net.fetchUrl(snippetsUri, maxAttempts: 2);
|
||||
if (data == null || data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
@ -145,7 +140,7 @@ class CreateCommand extends CreateBase {
|
||||
if (outputFile.existsSync()) {
|
||||
throwToolExit('File "$outputFilePath" already exists', exitCode: 1);
|
||||
}
|
||||
final String samplesJson = await _fetchSamplesIndexFromServer();
|
||||
final String? samplesJson = await _fetchSamplesIndexFromServer();
|
||||
if (samplesJson == null) {
|
||||
throwToolExit('Unable to download samples', exitCode: 2);
|
||||
} else {
|
||||
@ -158,11 +153,12 @@ class CreateCommand extends CreateBase {
|
||||
}
|
||||
|
||||
FlutterProjectType _getProjectType(Directory projectDir) {
|
||||
FlutterProjectType template;
|
||||
FlutterProjectType detectedProjectType;
|
||||
FlutterProjectType? template;
|
||||
FlutterProjectType? detectedProjectType;
|
||||
final bool metadataExists = projectDir.absolute.childFile('.metadata').existsSync();
|
||||
if (argResults['template'] != null) {
|
||||
template = stringToProjectType(stringArgDeprecated('template'));
|
||||
final String? templateArgument = stringArg('template');
|
||||
if (templateArgument != null) {
|
||||
template = stringToProjectType(templateArgument);
|
||||
}
|
||||
// If the project directory exists and isn't empty, then try to determine the template
|
||||
// type from the project directory.
|
||||
@ -188,23 +184,25 @@ class CreateCommand extends CreateBase {
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
if (argResults['list-samples'] != null) {
|
||||
final String? listSamples = stringArg('list-samples');
|
||||
if (listSamples != null) {
|
||||
// _writeSamplesJson can potentially be long-lived.
|
||||
await _writeSamplesJson(stringArgDeprecated('list-samples'));
|
||||
await _writeSamplesJson(listSamples);
|
||||
return FlutterCommandResult.success();
|
||||
}
|
||||
|
||||
validateOutputDirectoryArg();
|
||||
|
||||
String sampleCode;
|
||||
if (argResults['sample'] != null) {
|
||||
if (argResults['template'] != null &&
|
||||
stringToProjectType(stringArgDeprecated('template') ?? 'app') != FlutterProjectType.app) {
|
||||
String? sampleCode;
|
||||
final String? sampleArgument = stringArg('sample');
|
||||
if (sampleArgument != null) {
|
||||
final String? templateArgument = stringArg('template');
|
||||
if (templateArgument != null && stringToProjectType(templateArgument) != FlutterProjectType.app) {
|
||||
throwToolExit('Cannot specify --sample with a project type other than '
|
||||
'"${flutterProjectTypeToString(FlutterProjectType.app)}"');
|
||||
}
|
||||
// Fetch the sample from the server.
|
||||
sampleCode = await _fetchSampleFromServer(stringArgDeprecated('sample'));
|
||||
sampleCode = await _fetchSampleFromServer(sampleArgument);
|
||||
}
|
||||
|
||||
final FlutterProjectType template = _getProjectType(projectDir);
|
||||
@ -215,7 +213,7 @@ class CreateCommand extends CreateBase {
|
||||
|
||||
final List<String> platforms = stringsArg('platforms');
|
||||
// `--platforms` does not support module or package.
|
||||
if (argResults.wasParsed('platforms') && (generateModule || generatePackage)) {
|
||||
if (argResults!.wasParsed('platforms') && (generateModule || generatePackage)) {
|
||||
final String template = generateModule ? 'module' : 'package';
|
||||
throwToolExit(
|
||||
'The "--platforms" argument is not supported in $template template.',
|
||||
@ -224,18 +222,18 @@ class CreateCommand extends CreateBase {
|
||||
} else if (platforms == null || platforms.isEmpty) {
|
||||
throwToolExit('Must specify at least one platform using --platforms',
|
||||
exitCode: 2);
|
||||
} else if (generateFfiPlugin && argResults.wasParsed('platforms') && platforms.contains('web')) {
|
||||
} else if (generateFfiPlugin && argResults!.wasParsed('platforms') && platforms.contains('web')) {
|
||||
throwToolExit(
|
||||
'The web platform is not supported in plugin_ffi template.',
|
||||
exitCode: 2,
|
||||
);
|
||||
} else if (generateFfiPlugin && argResults.wasParsed('ios-language')) {
|
||||
} else if (generateFfiPlugin && argResults!.wasParsed('ios-language')) {
|
||||
throwToolExit(
|
||||
'The "ios-language" option is not supported with the plugin_ffi '
|
||||
'template: the language will always be C or C++.',
|
||||
exitCode: 2,
|
||||
);
|
||||
} else if (generateFfiPlugin && argResults.wasParsed('android-language')) {
|
||||
} else if (generateFfiPlugin && argResults!.wasParsed('android-language')) {
|
||||
throwToolExit(
|
||||
'The "android-language" option is not supported with the plugin_ffi '
|
||||
'template: the language will always be C or C++.',
|
||||
@ -258,7 +256,7 @@ class CreateCommand extends CreateBase {
|
||||
|
||||
final String dartSdk = globals.cache.dartSdkBuild;
|
||||
final bool includeIos = featureFlags.isIOSEnabled && platforms.contains('ios');
|
||||
String developmentTeam;
|
||||
String? developmentTeam;
|
||||
if (includeIos) {
|
||||
developmentTeam = await getCodeSigningIdentityDevelopmentTeam(
|
||||
processManager: globals.processManager,
|
||||
@ -272,7 +270,7 @@ class CreateCommand extends CreateBase {
|
||||
// The dart project_name is in snake_case, this variable is the Title Case of the Project Name.
|
||||
final String titleCaseProjectName = snakeCaseToTitleCase(projectName);
|
||||
|
||||
final Map<String, Object> templateContext = createTemplateContext(
|
||||
final Map<String, Object?> templateContext = createTemplateContext(
|
||||
organization: organization,
|
||||
projectName: projectName,
|
||||
titleCaseProjectName: titleCaseProjectName,
|
||||
@ -432,12 +430,12 @@ Your $application code is in $relativeAppMain.
|
||||
|
||||
Future<int> _generateModule(
|
||||
Directory directory,
|
||||
Map<String, dynamic> templateContext, {
|
||||
Map<String, Object?> templateContext, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
}) async {
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
final String? description = argResults!.wasParsed('description')
|
||||
? stringArgDeprecated('description')
|
||||
: 'A new Flutter module project.';
|
||||
templateContext['description'] = description;
|
||||
@ -453,7 +451,6 @@ Your $application code is in $relativeAppMain.
|
||||
context: PubContext.create,
|
||||
directory: directory.path,
|
||||
offline: boolArgDeprecated('offline'),
|
||||
generateSyntheticPackage: false,
|
||||
);
|
||||
final FlutterProject project = FlutterProject.fromDirectory(directory);
|
||||
await project.ensureReadyForPlatformSpecificTooling(
|
||||
@ -466,12 +463,12 @@ Your $application code is in $relativeAppMain.
|
||||
|
||||
Future<int> _generatePackage(
|
||||
Directory directory,
|
||||
Map<String, dynamic> templateContext, {
|
||||
Map<String, Object?> templateContext, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
}) async {
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
final String? description = argResults!.wasParsed('description')
|
||||
? stringArgDeprecated('description')
|
||||
: 'A new Flutter package project.';
|
||||
templateContext['description'] = description;
|
||||
@ -487,7 +484,6 @@ Your $application code is in $relativeAppMain.
|
||||
context: PubContext.createPackage,
|
||||
directory: directory.path,
|
||||
offline: boolArgDeprecated('offline'),
|
||||
generateSyntheticPackage: false,
|
||||
);
|
||||
}
|
||||
return generatedCount;
|
||||
@ -495,13 +491,13 @@ Your $application code is in $relativeAppMain.
|
||||
|
||||
Future<int> _generateMethodChannelPlugin(
|
||||
Directory directory,
|
||||
Map<String, dynamic> templateContext, {
|
||||
Map<String, Object?> templateContext, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
FlutterProjectType projectType,
|
||||
required FlutterProjectType projectType,
|
||||
}) async {
|
||||
// Plugins only add a platform if it was requested explicitly by the user.
|
||||
if (!argResults.wasParsed('platforms')) {
|
||||
if (!argResults!.wasParsed('platforms')) {
|
||||
for (final String platform in kAllCreatePlatforms) {
|
||||
templateContext[platform] = false;
|
||||
}
|
||||
@ -517,7 +513,7 @@ Your $application code is in $relativeAppMain.
|
||||
final bool willAddPlatforms = platformsToAdd.isNotEmpty;
|
||||
templateContext['no_platforms'] = !willAddPlatforms;
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
final String? description = argResults!.wasParsed('description')
|
||||
? stringArgDeprecated('description')
|
||||
: 'A new Flutter plugin project.';
|
||||
templateContext['description'] = description;
|
||||
@ -534,7 +530,6 @@ Your $application code is in $relativeAppMain.
|
||||
context: PubContext.createPlugin,
|
||||
directory: directory.path,
|
||||
offline: boolArgDeprecated('offline'),
|
||||
generateSyntheticPackage: false,
|
||||
);
|
||||
}
|
||||
|
||||
@ -545,9 +540,9 @@ Your $application code is in $relativeAppMain.
|
||||
project: project, requireAndroidSdk: false);
|
||||
}
|
||||
|
||||
final String projectName = templateContext['projectName'] as String;
|
||||
final String organization = templateContext['organization'] as String;
|
||||
final String androidPluginIdentifier = templateContext['androidIdentifier'] as String;
|
||||
final String? projectName = templateContext['projectName'] as String?;
|
||||
final String organization = templateContext['organization']! as String; // Required to make the context.
|
||||
final String? androidPluginIdentifier = templateContext['androidIdentifier'] as String?;
|
||||
final String exampleProjectName = '${projectName}_example';
|
||||
templateContext['projectName'] = exampleProjectName;
|
||||
templateContext['androidIdentifier'] = CreateBase.createAndroidIdentifier(organization, exampleProjectName);
|
||||
@ -572,13 +567,13 @@ Your $application code is in $relativeAppMain.
|
||||
|
||||
Future<int> _generateFfiPlugin(
|
||||
Directory directory,
|
||||
Map<String, dynamic> templateContext, {
|
||||
Map<String, Object?> templateContext, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
FlutterProjectType projectType,
|
||||
required FlutterProjectType projectType,
|
||||
}) async {
|
||||
// Plugins only add a platform if it was requested explicitly by the user.
|
||||
if (!argResults.wasParsed('platforms')) {
|
||||
if (!argResults!.wasParsed('platforms')) {
|
||||
for (final String platform in kAllCreatePlatforms) {
|
||||
templateContext[platform] = false;
|
||||
}
|
||||
@ -596,7 +591,7 @@ Your $application code is in $relativeAppMain.
|
||||
final bool willAddPlatforms = platformsToAdd.isNotEmpty;
|
||||
templateContext['no_platforms'] = !willAddPlatforms;
|
||||
int generatedCount = 0;
|
||||
final String description = argResults.wasParsed('description')
|
||||
final String? description = argResults!.wasParsed('description')
|
||||
? stringArgDeprecated('description')
|
||||
: 'A new Flutter FFI plugin project.';
|
||||
templateContext['description'] = description;
|
||||
@ -613,7 +608,6 @@ Your $application code is in $relativeAppMain.
|
||||
context: PubContext.createPlugin,
|
||||
directory: directory.path,
|
||||
offline: boolArgDeprecated('offline'),
|
||||
generateSyntheticPackage: false,
|
||||
);
|
||||
}
|
||||
|
||||
@ -623,9 +617,9 @@ Your $application code is in $relativeAppMain.
|
||||
gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
||||
}
|
||||
|
||||
final String projectName = templateContext['projectName'] as String;
|
||||
final String organization = templateContext['organization'] as String;
|
||||
final String androidPluginIdentifier = templateContext['androidIdentifier'] as String;
|
||||
final String? projectName = templateContext['projectName'] as String?;
|
||||
final String organization = templateContext['organization']! as String; // Required to make the context.
|
||||
final String? androidPluginIdentifier = templateContext['androidIdentifier'] as String?;
|
||||
final String exampleProjectName = '${projectName}_example';
|
||||
templateContext['projectName'] = exampleProjectName;
|
||||
templateContext['androidIdentifier'] = CreateBase.createAndroidIdentifier(organization, exampleProjectName);
|
||||
@ -662,7 +656,7 @@ Your $application code is in $relativeAppMain.
|
||||
return -files.length;
|
||||
}
|
||||
|
||||
List<String> _getSupportedPlatformsFromTemplateContext(Map<String, dynamic> templateContext) {
|
||||
List<String> _getSupportedPlatformsFromTemplateContext(Map<String, Object?> templateContext) {
|
||||
return <String>[
|
||||
for (String platform in kAllCreatePlatforms)
|
||||
if (templateContext[platform] == true) platform,
|
||||
@ -671,7 +665,7 @@ Your $application code is in $relativeAppMain.
|
||||
|
||||
// Returns a list of platforms that are explicitly requested by user via `--platforms`.
|
||||
List<String> _getUserRequestedPlatforms() {
|
||||
if (!argResults.wasParsed('platforms')) {
|
||||
if (!argResults!.wasParsed('platforms')) {
|
||||
return <String>[];
|
||||
}
|
||||
return stringsArg('platforms');
|
||||
@ -682,10 +676,11 @@ Your $application code is in $relativeAppMain.
|
||||
// Determine what platforms are supported based on generated files.
|
||||
List<String> _getSupportedPlatformsInPlugin(Directory projectDir) {
|
||||
final String pubspecPath = globals.fs.path.join(projectDir.absolute.path, 'pubspec.yaml');
|
||||
final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger);
|
||||
final List<String> platforms = manifest.validSupportedPlatforms == null
|
||||
final FlutterManifest? manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger);
|
||||
final Map<String, Object?>? validSupportedPlatforms = manifest?.validSupportedPlatforms;
|
||||
final List<String> platforms = validSupportedPlatforms == null
|
||||
? <String>[]
|
||||
: manifest.validSupportedPlatforms.keys.toList();
|
||||
: validSupportedPlatforms.keys.toList();
|
||||
return platforms;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
@ -54,7 +52,7 @@ const String _kDefaultPlatformArgumentHelp =
|
||||
/// Common behavior for `flutter create` commands.
|
||||
abstract class CreateBase extends FlutterCommand {
|
||||
CreateBase({
|
||||
@required bool verboseHelp,
|
||||
required bool verboseHelp,
|
||||
}) {
|
||||
argParser.addFlag(
|
||||
'pub',
|
||||
@ -64,7 +62,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
);
|
||||
argParser.addFlag(
|
||||
'offline',
|
||||
defaultsTo: false,
|
||||
help:
|
||||
'When "flutter pub get" is run by the create command, this indicates '
|
||||
'whether to run it in offline mode or not. In offline mode, it will need to '
|
||||
@ -72,8 +69,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
);
|
||||
argParser.addFlag(
|
||||
'with-driver-test',
|
||||
negatable: true,
|
||||
defaultsTo: false,
|
||||
help: '(deprecated) Historically, this added a flutter_driver dependency and generated a '
|
||||
'sample "flutter drive" test. Now it does nothing. Consider using the '
|
||||
'"integration_test" package: https://pub.dev/packages/integration_test',
|
||||
@ -81,8 +76,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
);
|
||||
argParser.addFlag(
|
||||
'overwrite',
|
||||
negatable: true,
|
||||
defaultsTo: false,
|
||||
help: 'When performing operations, overwrite existing files.',
|
||||
);
|
||||
argParser.addOption(
|
||||
@ -100,7 +93,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
);
|
||||
argParser.addOption(
|
||||
'project-name',
|
||||
defaultsTo: null,
|
||||
help:
|
||||
'The project name for this new Flutter project. This must be a valid dart package name.',
|
||||
);
|
||||
@ -134,7 +126,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
);
|
||||
argParser.addOption(
|
||||
'initial-create-revision',
|
||||
defaultsTo: null,
|
||||
help: 'The Flutter SDK git commit hash to store in .migrate_config. This parameter is used by the tool '
|
||||
'internally and should generally not be used manually.',
|
||||
hide: !verboseHelp,
|
||||
@ -144,7 +135,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
/// The output directory of the command.
|
||||
@protected
|
||||
Directory get projectDir {
|
||||
return globals.fs.directory(argResults.rest.first);
|
||||
return globals.fs.directory(argResults!.rest.first);
|
||||
}
|
||||
|
||||
/// The normalized absolute path of [projectDir].
|
||||
@ -157,7 +148,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
///
|
||||
/// The help message of the argument is replaced with `customHelp` if `customHelp` is not null.
|
||||
@protected
|
||||
void addPlatformsOptions({String customHelp}) {
|
||||
void addPlatformsOptions({String? customHelp}) {
|
||||
argParser.addMultiOption('platforms',
|
||||
help: customHelp ?? _kDefaultPlatformArgumentHelp,
|
||||
aliases: <String>[ 'platform' ],
|
||||
@ -173,16 +164,17 @@ abstract class CreateBase extends FlutterCommand {
|
||||
/// Throw with exit code 2 if the output directory is invalid.
|
||||
@protected
|
||||
void validateOutputDirectoryArg() {
|
||||
if (argResults.rest.isEmpty) {
|
||||
final List<String>? rest = argResults?.rest;
|
||||
if (rest == null || rest.isEmpty) {
|
||||
throwToolExit(
|
||||
'No option specified for the output directory.\n$usage',
|
||||
exitCode: 2,
|
||||
);
|
||||
}
|
||||
|
||||
if (argResults.rest.length > 1) {
|
||||
if (rest.length > 1) {
|
||||
String message = 'Multiple output directories specified.';
|
||||
for (final String arg in argResults.rest) {
|
||||
for (final String arg in rest) {
|
||||
if (arg.startsWith('-')) {
|
||||
message += '\nTry moving $arg to be immediately following $name';
|
||||
break;
|
||||
@ -194,7 +186,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
|
||||
/// Gets the flutter root directory.
|
||||
@protected
|
||||
String get flutterRoot => Cache.flutterRoot;
|
||||
String get flutterRoot => Cache.flutterRoot!;
|
||||
|
||||
/// Determines the project type in an existing flutter project.
|
||||
///
|
||||
@ -207,14 +199,15 @@ abstract class CreateBase extends FlutterCommand {
|
||||
/// Throws assertion if [projectDir] does not exist or empty.
|
||||
/// Returns null if no project type can be determined.
|
||||
@protected
|
||||
FlutterProjectType determineTemplateType() {
|
||||
FlutterProjectType? determineTemplateType() {
|
||||
assert(projectDir.existsSync() && projectDir.listSync().isNotEmpty);
|
||||
final File metadataFile = globals.fs
|
||||
.file(globals.fs.path.join(projectDir.absolute.path, '.metadata'));
|
||||
final FlutterProjectMetadata projectMetadata =
|
||||
FlutterProjectMetadata(metadataFile, globals.logger);
|
||||
if (projectMetadata.projectType != null) {
|
||||
return projectMetadata.projectType;
|
||||
final FlutterProjectType? projectType = projectMetadata.projectType;
|
||||
if (projectType != null) {
|
||||
return projectType;
|
||||
}
|
||||
|
||||
bool exists(List<String> path) {
|
||||
@ -243,8 +236,8 @@ abstract class CreateBase extends FlutterCommand {
|
||||
/// If `--org` is not specified, returns the organization from the existing project.
|
||||
@protected
|
||||
Future<String> getOrganization() async {
|
||||
String organization = stringArgDeprecated('org');
|
||||
if (!argResults.wasParsed('org')) {
|
||||
String? organization = stringArgDeprecated('org');
|
||||
if (!argResults!.wasParsed('org')) {
|
||||
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
|
||||
final Set<String> existingOrganizations = await project.organizationNames;
|
||||
if (existingOrganizations.length == 1) {
|
||||
@ -255,6 +248,9 @@ abstract class CreateBase extends FlutterCommand {
|
||||
'The --org command line argument must be specified to recreate project.');
|
||||
}
|
||||
}
|
||||
if (organization == null) {
|
||||
throwToolExit('The --org command line argument must be specified to create a project.');
|
||||
}
|
||||
return organization;
|
||||
}
|
||||
|
||||
@ -297,12 +293,10 @@ abstract class CreateBase extends FlutterCommand {
|
||||
// Do not overwrite files.
|
||||
throwToolExit("Invalid project name: '$projectDirPath' - file exists.",
|
||||
exitCode: 2);
|
||||
break;
|
||||
case FileSystemEntityType.link:
|
||||
// Do not overwrite links.
|
||||
throwToolExit("Invalid project name: '$projectDirPath' - refers to a link.",
|
||||
exitCode: 2);
|
||||
break;
|
||||
case FileSystemEntityType.directory:
|
||||
case FileSystemEntityType.notFound:
|
||||
break;
|
||||
@ -317,7 +311,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
final String projectName =
|
||||
stringArgDeprecated('project-name') ?? globals.fs.path.basename(projectDirPath);
|
||||
if (!boolArgDeprecated('skip-name-checks')) {
|
||||
final String error = _validateProjectName(projectName);
|
||||
final String? error = _validateProjectName(projectName);
|
||||
if (error != null) {
|
||||
throwToolExit(error);
|
||||
}
|
||||
@ -328,19 +322,19 @@ abstract class CreateBase extends FlutterCommand {
|
||||
|
||||
/// Creates a template to use for [renderTemplate].
|
||||
@protected
|
||||
Map<String, Object> createTemplateContext({
|
||||
String organization,
|
||||
String projectName,
|
||||
String titleCaseProjectName,
|
||||
String projectDescription,
|
||||
String androidLanguage,
|
||||
String iosDevelopmentTeam,
|
||||
String iosLanguage,
|
||||
String flutterRoot,
|
||||
String dartSdkVersionBounds,
|
||||
String agpVersion,
|
||||
String kotlinVersion,
|
||||
String gradleVersion,
|
||||
Map<String, Object?> createTemplateContext({
|
||||
required String organization,
|
||||
required String projectName,
|
||||
required String titleCaseProjectName,
|
||||
String? projectDescription,
|
||||
String? androidLanguage,
|
||||
String? iosDevelopmentTeam,
|
||||
String? iosLanguage,
|
||||
required String flutterRoot,
|
||||
required String dartSdkVersionBounds,
|
||||
String? agpVersion,
|
||||
String? kotlinVersion,
|
||||
String? gradleVersion,
|
||||
bool withPlatformChannelPluginHook = false,
|
||||
bool withFfiPluginHook = false,
|
||||
bool ios = false,
|
||||
@ -376,7 +370,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
? globals.flutterVersion.frameworkVersion
|
||||
: ffiPluginStableRelease.toString();
|
||||
|
||||
return <String, Object>{
|
||||
return <String, Object?>{
|
||||
'organization': organization,
|
||||
'projectName': projectName,
|
||||
'titleCaseProjectName': titleCaseProjectName,
|
||||
@ -433,7 +427,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
Future<int> renderTemplate(
|
||||
String templateName,
|
||||
Directory directory,
|
||||
Map<String, Object> context, {
|
||||
Map<String, Object?> context, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
}) async {
|
||||
@ -461,7 +455,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
Future<int> renderMerged(
|
||||
List<String> names,
|
||||
Directory directory,
|
||||
Map<String, Object> context, {
|
||||
Map<String, Object?> context, {
|
||||
bool overwrite = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
}) async {
|
||||
@ -488,12 +482,12 @@ abstract class CreateBase extends FlutterCommand {
|
||||
Future<int> generateApp(
|
||||
List<String> templateNames,
|
||||
Directory directory,
|
||||
Map<String, Object> templateContext, {
|
||||
Map<String, Object?> templateContext, {
|
||||
bool overwrite = false,
|
||||
bool pluginExampleApp = false,
|
||||
bool printStatusWhenWriting = true,
|
||||
bool generateMetadata = true,
|
||||
FlutterProjectType projectType,
|
||||
FlutterProjectType? projectType,
|
||||
}) async {
|
||||
int generatedCount = 0;
|
||||
generatedCount += await renderMerged(
|
||||
@ -508,16 +502,16 @@ abstract class CreateBase extends FlutterCommand {
|
||||
generatedCount += _injectGradleWrapper(project);
|
||||
}
|
||||
|
||||
final bool androidPlatform = templateContext['android'] as bool ?? false;
|
||||
final bool iosPlatform = templateContext['ios'] as bool ?? false;
|
||||
final bool linuxPlatform = templateContext['linux'] as bool ?? false;
|
||||
final bool macOSPlatform = templateContext['macos'] as bool ?? false;
|
||||
final bool windowsPlatform = templateContext['windows'] as bool ?? false;
|
||||
final bool webPlatform = templateContext['web'] as bool ?? false;
|
||||
final bool androidPlatform = templateContext['android'] as bool? ?? false;
|
||||
final bool iosPlatform = templateContext['ios'] as bool? ?? false;
|
||||
final bool linuxPlatform = templateContext['linux'] as bool? ?? false;
|
||||
final bool macOSPlatform = templateContext['macos'] as bool? ?? false;
|
||||
final bool windowsPlatform = templateContext['windows'] as bool? ?? false;
|
||||
final bool webPlatform = templateContext['web'] as bool? ?? false;
|
||||
|
||||
if (boolArgDeprecated('pub')) {
|
||||
final Environment environment = Environment(
|
||||
artifacts: globals.artifacts,
|
||||
artifacts: globals.artifacts!,
|
||||
logger: globals.logger,
|
||||
cacheDir: globals.cache.getRoot(),
|
||||
engineVersion: globals.flutterVersion.engineRevision,
|
||||
@ -591,7 +585,6 @@ abstract class CreateBase extends FlutterCommand {
|
||||
metadata.populate(
|
||||
platforms: platformsForMigrateConfig,
|
||||
projectDirectory: directory,
|
||||
create: true,
|
||||
update: false,
|
||||
currentRevision: stringArgDeprecated('initial-create-revision') ?? globals.flutterVersion.frameworkRevision,
|
||||
createRevision: globals.flutterVersion.frameworkRevision,
|
||||
@ -663,12 +656,10 @@ abstract class CreateBase extends FlutterCommand {
|
||||
return segments.join('.');
|
||||
}
|
||||
|
||||
Set<Uri> get _templateManifest =>
|
||||
__templateManifest ??= _computeTemplateManifest();
|
||||
Set<Uri> __templateManifest;
|
||||
late final Set<Uri> _templateManifest = _computeTemplateManifest();
|
||||
Set<Uri> _computeTemplateManifest() {
|
||||
final String flutterToolsAbsolutePath = globals.fs.path.join(
|
||||
Cache.flutterRoot,
|
||||
Cache.flutterRoot!,
|
||||
'packages',
|
||||
'flutter_tools',
|
||||
);
|
||||
@ -681,7 +672,7 @@ abstract class CreateBase extends FlutterCommand {
|
||||
globals.fs.file(manifestPath).readAsStringSync(),
|
||||
) as Map<String, Object>;
|
||||
return Set<Uri>.from(
|
||||
(manifest['files'] as List<Object>).cast<String>().map<Uri>(
|
||||
(manifest['files']! as List<Object>).cast<String>().map<Uri>(
|
||||
(String path) =>
|
||||
Uri.file(globals.fs.path.join(flutterToolsAbsolutePath, path))),
|
||||
);
|
||||
@ -793,7 +784,7 @@ const Set<String> _packageDependencies = <String>{
|
||||
/// Whether [name] is a valid Pub package.
|
||||
@visibleForTesting
|
||||
bool isValidPackageName(String name) {
|
||||
final Match match = _identifierRegExp.matchAsPrefix(name);
|
||||
final Match? match = _identifierRegExp.matchAsPrefix(name);
|
||||
return match != null &&
|
||||
match.end == name.length &&
|
||||
!_keywords.contains(name);
|
||||
@ -801,7 +792,7 @@ bool isValidPackageName(String name) {
|
||||
|
||||
// Return null if the project name is legal. Return a validation message if
|
||||
// we should disallow the project name.
|
||||
String _validateProjectName(String projectName) {
|
||||
String? _validateProjectName(String projectName) {
|
||||
if (!isValidPackageName(projectName)) {
|
||||
return '"$projectName" is not a valid Dart package name.\n\n'
|
||||
'See https://dart.dev/tools/pub/pubspec#name for more information.';
|
||||
|
@ -155,7 +155,7 @@ class Template {
|
||||
/// May throw a [ToolExit] if the directory is not writable.
|
||||
int render(
|
||||
Directory destination,
|
||||
Map<String, Object> context, {
|
||||
Map<String, Object?> context, {
|
||||
bool overwriteExisting = true,
|
||||
bool printStatusWhenWriting = true,
|
||||
}) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
@ -20,7 +18,7 @@ import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
|
||||
|
||||
export 'package:test_api/test_api.dart' hide test, isInstanceOf; // ignore: deprecated_member_use
|
||||
|
||||
CommandRunner<void> createTestCommandRunner([ FlutterCommand command ]) {
|
||||
CommandRunner<void> createTestCommandRunner([ FlutterCommand? command ]) {
|
||||
final FlutterCommandRunner runner = TestFlutterCommandRunner();
|
||||
if (command != null) {
|
||||
runner.addCommand(command);
|
||||
@ -31,7 +29,7 @@ CommandRunner<void> createTestCommandRunner([ FlutterCommand command ]) {
|
||||
/// Creates a flutter project in the [temp] directory using the
|
||||
/// [arguments] list if specified, or `--no-pub` if not.
|
||||
/// Returns the path to the flutter project.
|
||||
Future<String> createProject(Directory temp, { List<String> arguments }) async {
|
||||
Future<String> createProject(Directory temp, { List<String>? arguments }) async {
|
||||
arguments ??= <String>['--no-pub'];
|
||||
final String projectPath = globals.fs.path.join(temp.path, 'flutter_project');
|
||||
final CreateCommand command = CreateCommand();
|
||||
@ -61,7 +59,7 @@ class TestFlutterCommandRunner extends FlutterCommandRunner {
|
||||
userMessages: UserMessages(),
|
||||
);
|
||||
// For compatibility with tests that set this to a relative path.
|
||||
Cache.flutterRoot = globals.fs.path.normalize(globals.fs.path.absolute(Cache.flutterRoot));
|
||||
Cache.flutterRoot = globals.fs.path.normalize(globals.fs.path.absolute(Cache.flutterRoot!));
|
||||
return super.runCommand(topLevelResults);
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user