Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tool] Proposal to support dart define config from a json file #108098

Merged
merged 47 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3f29a14
add new flag support config json constant
hai046 Jul 5, 2022
454f7c0
add usage
hai046 Jul 5, 2022
cbf55ec
Merge branch 'master' into fea-json-config
hai046 Jul 5, 2022
23a6fd0
1、update option to --dart-define-from-file
hai046 Jul 19, 2022
1d5518a
update define name,support macOS
hai046 Jul 19, 2022
ba907ea
add cmd option commit
hai046 Jul 19, 2022
deebb3a
1、add new flag `enable-dart-define-from-file-raw-value` ;2、get raw j…
hai046 Jul 21, 2022
1db1587
fix: flutter-dashboard test case
hai046 Jul 21, 2022
668dfd2
fix: flutter-dashboard test case sort import
hai046 Jul 21, 2022
a848a7f
Merge pull request #1 from flutter/master
hai046 Jul 21, 2022
dd6025f
Merge pull request #2 from hai046/fea-json-config
hai046 Jul 21, 2022
fad326d
Merge pull request #3 from hai046/master
hai046 Jul 21, 2022
0fc0e3c
Modify and optimize according to the guidelines: https://github.com/f…
hai046 Aug 17, 2022
63180b4
Modify and optimize according to the guidelines: https://github.com/f…
hai046 Aug 17, 2022
86fc568
Modify and optimize according to the guidelines: https://github.com/f…
hai046 Aug 17, 2022
c80a9bd
delete no use code
hai046 Aug 17, 2022
2bb6883
Optimize filed usage
hai046 Aug 18, 2022
84f48ea
Merge pull request #4 from flutter/master
hai046 Aug 18, 2022
c5e784c
Merge branch 'master' into fea-json-config
hai046 Aug 18, 2022
5b58333
Merge pull request #5 from flutter/master
hai046 Aug 18, 2022
e25f2e1
Merge branch 'master' into fea-json-config
hai046 Aug 18, 2022
ab8ea32
add ""--dart-define-from-file option" and "enable-dart-define-from-fi…
hai046 Aug 22, 2022
58c4210
Merge pull request #6 from flutter/master
hai046 Aug 22, 2022
73a62fc
Merge branch 'master' into fea-json-config
hai046 Aug 22, 2022
6938e52
Thanks to christopherfujino for the suggestion, modify the code as su…
hai046 Aug 26, 2022
48ccf3c
format code
hai046 Aug 26, 2022
c69ded2
Merge pull request #7 from flutter/master
hai046 Aug 26, 2022
b023ef1
Merge branch 'master' into fea-json-config
hai046 Aug 26, 2022
19939ac
delete enable-dart-define-from-file-raw-value
hai046 Aug 26, 2022
22efe8b
Merge pull request #8 from flutter/master
hai046 Sep 14, 2022
6ea4502
Merge branch 'master' into fea-json-config
hai046 Sep 14, 2022
61f5aab
1、Guidance on modifying documents by Jasguerrero
hai046 Sep 14, 2022
fb88c0c
fix json convert Object value :type '_InternalLinkedHashMap<String, d…
hai046 Sep 14, 2022
291f391
reformat code comments
hai046 Sep 14, 2022
0adde35
Merge pull request #9 from flutter/master
hai046 Sep 14, 2022
d39e96f
del unused_import
hai046 Sep 14, 2022
de2be28
优化usesDartDefineOption
hai046 Sep 16, 2022
05f4af9
Optimize variable usage to prevent overwriting in extreme cases
hai046 Sep 20, 2022
c8e7f28
Merge pull request #10 from flutter/master
hai046 Sep 20, 2022
3fb643e
Merge branch 'master' into fea-json-config
hai046 Sep 20, 2022
d047ec9
Merge pull request #11 from flutter/master
hai046 Sep 20, 2022
8bfd25c
Merge branch 'master' into fea-json-config
hai046 Sep 20, 2022
f39df3a
replace implementation method
hai046 Sep 21, 2022
b99be07
Understand ambiguity, restore implementation
hai046 Sep 23, 2022
37a50d6
Merge pull request #12 from flutter/master
hai046 Sep 23, 2022
2754935
Merge branch 'master' into fea-json-config
hai046 Sep 23, 2022
440df60
Simulate operation flutterCommand.getBuildInfo with `dart-define-fro…
hai046 Sep 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 43 additions & 2 deletions packages/flutter_tools/lib/src/build_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class BuildInfo {
List<String>? dartExperiments,
required this.treeShakeIcons,
this.performanceMeasurementFile,
this.dartDefineConfigJsonMap,
this.packagesPath = '.dart_tool/package_config.json', // TODO(zanderso): make this required and remove the default.
this.nullSafetyMode = NullSafetyMode.sound,
this.codeSizeDirectory,
Expand Down Expand Up @@ -130,6 +131,17 @@ class BuildInfo {
/// rerun tasks.
final String? performanceMeasurementFile;

/// Configure a constant pool file.
/// Additional constant values to be made available in the Dart program.
///
/// These values can be used with the const `fromEnvironment` constructors of
/// [String] the key and field are json values
/// json value
///
/// An additional field `dartDefineConfigJsonMap` is provided to represent the native JSON value of the configuration file
///
final Map<String, Object>? dartDefineConfigJsonMap;

/// If provided, an output directory where one or more v8-style heap snapshots
/// will be written for code size profiling.
final String? codeSizeDirectory;
Expand Down Expand Up @@ -247,12 +259,17 @@ class BuildInfo {
};
}


/// Convert to a structured string encoded structure appropriate for usage as
/// environment variables or to embed in other scripts.
///
/// Fields that are `null` are excluded from this configuration.
Map<String, String> toEnvironmentConfig() {
return <String, String>{
final Map<String, String> map = <String, String>{};
dartDefineConfigJsonMap?.forEach((String key, Object value) {
map[key] = '$value';
});
final Map<String, String> environmentMap = <String, String>{
if (dartDefines.isNotEmpty)
'DART_DEFINES': encodeDartDefines(dartDefines),
hai046 marked this conversation as resolved.
Show resolved Hide resolved
if (dartObfuscation != null)
Expand All @@ -276,13 +293,23 @@ class BuildInfo {
if (codeSizeDirectory != null)
'CODE_SIZE_DIRECTORY': codeSizeDirectory!,
};
map.forEach((String key, String value) {
if (environmentMap.containsKey(key)) {
globals.printWarning(
'The key: [$key] already exists, you cannot use environment variables that have been used by the system!');
} else {
// System priority is greater than user priority
environmentMap[key] = value;
}
});
return environmentMap;
}

/// Convert this config to a series of project level arguments to be passed
/// on the command line to gradle.
List<String> toGradleConfig() {
// PACKAGE_CONFIG not currently supported.
return <String>[
final List<String> result = <String>[
if (dartDefines.isNotEmpty)
'-Pdart-defines=${encodeDartDefines(dartDefines)}',
if (dartObfuscation != null)
Expand All @@ -306,6 +333,20 @@ class BuildInfo {
for (String projectArg in androidProjectArgs)
'-P$projectArg',
];
if(dartDefineConfigJsonMap != null) {
final List<String> items = <String>[];
for (final String gradleConf in result) {
final String key = gradleConf.split('=')[0].substring(2);
if (dartDefineConfigJsonMap!.containsKey(key)) {
globals.printWarning(
'The key: [$key] already exists, you cannot use gradle variables that have been used by the system!');
} else {
items.add('-P$key=${dartDefineConfigJsonMap?[key]}');
}
}
result.addAll(items);
}
return result;
}
}

Expand Down
22 changes: 21 additions & 1 deletion packages/flutter_tools/lib/src/commands/assemble.dart
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,29 @@ class AssembleCommand extends FlutterCommand {
if (argumentResults.wasParsed(FlutterOptions.kExtraGenSnapshotOptions)) {
results[kExtraGenSnapshotOptions] = (argumentResults[FlutterOptions.kExtraGenSnapshotOptions] as List<String>).join(',');
}

List<String> dartDefines = <String>[];
if (argumentResults.wasParsed(FlutterOptions.kDartDefinesOption)) {
results[kDartDefines] = (argumentResults[FlutterOptions.kDartDefinesOption] as List<String>).join(',');
dartDefines = argumentResults[FlutterOptions.kDartDefinesOption] as List<String>;
}
if (argumentResults.wasParsed(FlutterOptions.kDartDefineFromFileOption)) {
final String? configJsonPath = stringArg(FlutterOptions.kDartDefineFromFileOption);
if (configJsonPath != null && globals.fs.isFileSync(configJsonPath)) {
final String configJsonRaw = globals.fs.file(configJsonPath).readAsStringSync();
try {
(json.decode(configJsonRaw) as Map<String, dynamic>).forEach((String key, dynamic value) {
dartDefines.add('$key=$value');
});
} on FormatException catch (err) {
throwToolExit('Json config define file "--${FlutterOptions.kDartDefineFromFileOption}=$configJsonPath" format err, '
'please fix first! format err:\n$err');
}
}
}
if(dartDefines.isNotEmpty){
results[kDartDefines] = dartDefines.join(',');
}

results[kDeferredComponents] = 'false';
if (FlutterProject.current().manifest.deferredComponents != null && isDeferredComponentsTargets() && !isDebug()) {
results[kDeferredComponents] = 'true';
Expand Down
35 changes: 35 additions & 0 deletions packages/flutter_tools/lib/src/runner/flutter_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import '../build_info.dart';
import '../build_system/build_system.dart';
import '../bundle.dart' as bundle;
import '../cache.dart';
import '../convert.dart';
import '../dart/generate_synthetic_packages.dart';
import '../dart/language_version.dart';
import '../dart/package_map.dart';
Expand Down Expand Up @@ -104,6 +105,7 @@ class FlutterOptions {
static const String kSplitDebugInfoOption = 'split-debug-info';
static const String kDartObfuscationOption = 'obfuscate';
static const String kDartDefinesOption = 'dart-define';
static const String kDartDefineFromFileOption = 'dart-define-from-file';
static const String kBundleSkSLPathOption = 'bundle-sksl-path';
static const String kPerformanceMeasurementFile = 'performance-measurement-file';
static const String kNullSafety = 'sound-null-safety';
Expand Down Expand Up @@ -591,6 +593,17 @@ abstract class FlutterCommand extends Command<void> {
valueHelp: 'foo=bar',
splitCommas: false,
);
useDartDefineConfigJsonFileOption();
}

void useDartDefineConfigJsonFileOption() {
argParser.addOption(
FlutterOptions.kDartDefineFromFileOption,
help: 'The path of a json format file where flutter define a global constant pool. '
'Json entry will be available as constants from the String.fromEnvironment, bool.fromEnvironment, '
'int.fromEnvironment, and double.fromEnvironment constructors; the key and field are json values.',
valueHelp: 'use-define-config.json'
);
}

void usesWebRendererOption() {
Expand Down Expand Up @@ -1122,6 +1135,27 @@ abstract class FlutterCommand extends Command<void> {
dartDefines = updateDartDefines(dartDefines, stringArgDeprecated('web-renderer')!);
}

Map<String, Object>? defineConfigJsonMap;
if (argParser.options.containsKey(FlutterOptions.kDartDefineFromFileOption)) {
final String? configJsonPath = stringArg(FlutterOptions.kDartDefineFromFileOption);
if (configJsonPath != null && globals.fs.isFileSync(configJsonPath)) {
final String configJsonRaw = globals.fs.file(configJsonPath).readAsStringSync();
try {
defineConfigJsonMap = <String, Object>{};
// Fix json convert Object value :type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Map<String, Object>' in type cast
(json.decode(configJsonRaw) as Map<String, dynamic>).forEach((String key, dynamic value) {
defineConfigJsonMap?[key]=value as Object;
});
defineConfigJsonMap.forEach((String key, Object value) {
dartDefines.add('$key=$value');
});
} on FormatException catch (err) {
throwToolExit('Json config define file "--${FlutterOptions.kDartDefineFromFileOption}=$configJsonPath" format err, '
'please fix first! format err:\n$err');
}
}
}

return BuildInfo(buildMode,
argParser.options.containsKey('flavor')
? stringArgDeprecated('flavor')
Expand All @@ -1146,6 +1180,7 @@ abstract class FlutterCommand extends Command<void> {
bundleSkSLPath: bundleSkSLPath,
dartExperiments: experiments,
performanceMeasurementFile: performanceMeasurementFile,
dartDefineConfigJsonMap: defineConfigJsonMap,
packagesPath: packagesPath ?? globals.fs.path.absolute('.dart_tool', 'package_config.json'),
nullSafetyMode: nullSafetyMode,
codeSizeDirectory: codeSizeDirectory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,33 @@ void main() {
],
});
});

testUsingContext('test --dart-define-from-file option with err json format', () async {
await globals.fs.file('config.json').writeAsString(
'''
{
"kInt": 1,
"kDouble": 1.1,
"name": "err json format,
"title": "this is title from config json file"
}
'''
);
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
));

expect(commandRunner.run(<String>['assemble',
'-o Output',
'debug_macos_bundle_flutter_assets',
'--dart-define=k=v',
'--dart-define-from-file=config.json']),
throwsToolExit(message: 'Json config define file "--dart-define-from-file=config.json" format err, please fix first! format err:'));
}, overrides: <Type, Generator>{
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});


}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
Expand Down Expand Up @@ -463,6 +464,64 @@ void main() {
FileSystem: fsFactory,
ProcessManager: () => FakeProcessManager.any(),
});

testUsingContext('test --dart-define-from-file option', () async {
hai046 marked this conversation as resolved.
Show resolved Hide resolved
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
await globals.fs.file('config.json').writeAsString(
'''
{
"kInt": 1,
"kDouble": 1.1,
"name": "denghaizhu",
"title": "this is title from config json file"
}
'''
);
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());

await runner.run(<String>[
'bundle',
'--no-pub',
'--dart-define-from-file=config.json',
]);
}, overrides: <Type, Generator>{
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines[kDartDefines], 'a0ludD0x,a0RvdWJsZT0xLjE=,bmFtZT1kZW5naGFpemh1,dGl0bGU9dGhpcyBpcyB0aXRsZSBmcm9tIGNvbmZpZyBqc29uIGZpbGU=');
}),
FileSystem: fsFactory,
ProcessManager: () => FakeProcessManager.any(),
});


testUsingContext('test --dart-define-from-file option by corrupted json', () async {
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
await globals.fs.file('config.json').writeAsString(
'''
{
"kInt": 1Error json format
"kDouble": 1.1,
"name": "denghaizhu",
"title": "this is title from config json file"
}
'''
);
final CommandRunner<void> runner = createTestCommandRunner(BuildBundleCommand());

expect(() => runner.run(<String>[
'bundle',
'--no-pub',
'--dart-define-from-file=config.json',
]), throwsA(predicate<Exception>((Exception e) => e is ToolExit && e.message!.startsWith('Json config define file "--dart-define-from-file=config.json" format err'))));
}, overrides: <Type, Generator>{
FileSystem: fsFactory,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
ProcessManager: () => FakeProcessManager.any(),
});

}

class FakeBundleBuilder extends Fake implements BundleBuilder {
Expand Down
67 changes: 67 additions & 0 deletions packages/flutter_tools/test/general.shard/build_info_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';

import '../src/common.dart';
import '../src/context.dart';

void main() {
late BufferLogger logger;
Expand Down Expand Up @@ -279,4 +280,70 @@ void main() {
kDartDefines: 'MTIzMiw0NTY=,Mg==',
}, kDartDefines), <String>['1232,456', '2']);
});

group('Check repeated buildInfo variables', () {
testUsingContext('toEnvironmentConfig repeated variable', () async {
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
treeShakeIcons: true,
trackWidgetCreation: true,
dartDefines: <String>['foo=2', 'bar=2'],
dartDefineConfigJsonMap: <String,Object>{ 'DART_DEFINES' : 'Define a variable, but it occupies the variable name of the system'},
dartObfuscation: true,
);
buildInfo.toEnvironmentConfig();
expect(testLogger.warningText, contains('The key: [DART_DEFINES] already exists, you cannot use environment variables that have been used by the system'));
hai046 marked this conversation as resolved.
Show resolved Hide resolved
});

testUsingContext('toEnvironmentConfig repeated variable with DART_DEFINES not set', () async {
// Simulate operation flutterCommand.getBuildInfo with `dart-define-from-file` set dartDefines
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
treeShakeIcons: true,
dartDefines: <String>['DART_DEFINES=Define a variable, but it occupies the variable name of the system'],
trackWidgetCreation: true,
dartDefineConfigJsonMap: <String, Object>{ 'DART_DEFINES' : 'Define a variable, but it occupies the variable name of the system'},
dartObfuscation: true,
);
buildInfo.toEnvironmentConfig();
expect(testLogger.warningText, contains('The key: [DART_DEFINES] already exists, you cannot use environment variables that have been used by the system'));

});

testUsingContext('toGradleConfig repeated variable', () async {
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
treeShakeIcons: true,
trackWidgetCreation: true,
dartDefines: <String>['foo=2', 'bar=2'],
dartDefineConfigJsonMap: <String,Object>{ 'dart-defines' : 'Define a variable, but it occupies the variable name of the system'},
dartObfuscation: true,
);
buildInfo.toGradleConfig();
expect(testLogger.warningText, contains('he key: [dart-defines] already exists, you cannot use gradle variables that have been used by the system'));
});

testUsingContext('toGradleConfig repeated variable with not set', () async {
// Simulate operation flutterCommand.getBuildInfo with `dart-define-from-file` set dartDefines
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
treeShakeIcons: true,
trackWidgetCreation: true,
dartDefines: <String>['dart-defines=Define a variable, but it occupies the variable name of the system'],
dartDefineConfigJsonMap: <String,Object>{ 'dart-defines' : 'Define a variable, but it occupies the variable name of the system'},
dartObfuscation: true,
);
buildInfo.toGradleConfig();
expect(testLogger.warningText, contains('he key: [dart-defines] already exists, you cannot use gradle variables that have been used by the system'));
});

testUsingContext('toGradleConfig with androidProjectArgs override gradle project variant', () async {
const BuildInfo buildInfo = BuildInfo(BuildMode.debug, '',
treeShakeIcons: true,
trackWidgetCreation: true,
androidProjectArgs: <String>['applicationId=com.google'],
dartDefineConfigJsonMap: <String,Object>{ 'applicationId' : 'override applicationId'},
dartObfuscation: true,
);
buildInfo.toGradleConfig();
expect(testLogger.warningText, contains('The key: [applicationId] already exists, you cannot use gradle variables that have been used'));
});

});
}