[pigeon] 0.2.0 Made null-safe generation the default, updated documentation (#315)

- fix for niladic java functions
- tweak to runCommandLine
This commit is contained in:
gaaclarke
2021-03-29 10:16:38 -07:00
committed by GitHub
parent 0e408ef8ac
commit 1378c443a1
8 changed files with 76 additions and 34 deletions

View File

@ -1,3 +1,30 @@
## 0.2.0
* **BREAKING CHANGE** - Pigeon files must be null-safe now. That means the
fields inside of the classes must be declared nullable (
[non-null fields](https://github.com/flutter/flutter/issues/59118) arent't yet
supported). Migration example:
```dart
// Version 0.1.x
class Foo {
int bar;
String baz;
}
// Version 0.2.x
class Foo {
int? bar;
String? baz;
}
```
* **BREAKING CHANGE** - The default output from Pigeon is now null-safe. If you
want non-null-safe code you must provide the `--no-dart_null_safety` flag.
* The Pigeon source code is now null-safe.
* Fixed niladic non-value returning async functions in the Java generator.
* Made `runCommandLine` return an the status code.
## 0.1.24
* Moved logic from bin/ to lib/ to help customers wrap up the behavior.

View File

@ -8,8 +8,9 @@ host platform type-safe and easier.
## Supported Platforms
Currently Pigeon only supports generating Objective-C code for usage on iOS and
Java code for Android. The Objective-C code is [accessible to Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_objective-c_into_swift) and the Java
code is accessible to Kotlin.
Java code for Android. The Objective-C code is
[accessible to Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_objective-c_into_swift)
and the Java code is accessible to Kotlin.
## Runtime Requirements
@ -64,7 +65,8 @@ See the "Example" tab. A full working example can also be found in the
Pigeon uses the `StandardMessageCodec` so it supports any data-type platform
channels supports
[[documentation](https://flutter.dev/docs/development/platform-integration/platform-channels#codec)]. Nested data-types are supported, too.
[[documentation](https://flutter.dev/docs/development/platform-integration/platform-channels#codec)].
Nested data-types are supported, too.
Note: Generics for List and Map aren't supported yet.
@ -112,9 +114,12 @@ public interface Api2Host {
## Null Safety (NNBD)
In order to generate null-safe code run the command line with the extra argument
`--dart_null_safety`. For example:
`flutter pub run pigeon --input ./pigeons/messages.dart --dart_null_safety`.
Right now Pigeon supports generating null-safe code, but it doesn't yet support
[non-null fields](https://github.com/flutter/flutter/issues/59118).
The default is to generate null-safe code but in order to generate non-null-safe
code run Pigeon with the extra argument `--no-dart_null_safety`. For example:
`flutter pub run pigeon --input ./pigeons/messages.dart --no-dart_null_safety --dart_out stdout`.
## Feedback

View File

@ -4,8 +4,10 @@
// @dart = 2.2
import 'dart:io' show exit;
import 'package:pigeon/pigeon_cl.dart';
Future<void> main(List<String> args) async {
await runCommandLine(args);
exit(await runCommandLine(args));
}

View File

@ -7,8 +7,11 @@ import 'generator_tools.dart';
/// Options that control how Dart code will be generated.
class DartOptions {
/// Constructor for DartOptions.
DartOptions({this.isNullSafe = true});
/// Determines if the generated code has null safety annotations (Dart >=2.12 required).
bool isNullSafe = false;
bool isNullSafe;
}
String _escapeForDartSingleQuotedString(String raw) {

View File

@ -27,7 +27,7 @@ String _posixRelative(String input, {required String from}) {
/// This is the main entrypoint for the command-line tool. [args] are the
/// commmand line arguments and there is an optional [packageConfig] to
/// accomodate users that want to integrate pigeon with other build systems.
Future<void> runCommandLine(List<String> args, {Uri? packageConfig}) async {
Future<int> runCommandLine(List<String> args, {Uri? packageConfig}) async {
final PigeonOptions opts = Pigeon.parseArgs(args);
final Directory tempDir = Directory.systemTemp.createTempSync(
'flutter_pigeon.',
@ -71,5 +71,5 @@ void main(List<String> args, SendPort sendPort) async {
});
final int exitCode = await completer.future;
tempDir.deleteSync(recursive: true);
exit(exitCode);
return exitCode;
}

View File

@ -313,7 +313,8 @@ options:
..addOption('java_package',
help: 'The package that generated Java code will be in.')
..addFlag('dart_null_safety',
help: 'Makes generated Dart code have null safety annotations')
help: 'Makes generated Dart code have null safety annotations',
defaultsTo: true)
..addOption('objc_header_out',
help: 'Path to generated Objective-C header file (.h).')
..addOption('objc_prefix',
@ -321,6 +322,10 @@ options:
/// Convert command-line arguments to [PigeonOptions].
static PigeonOptions parseArgs(List<String> args) {
// Note: This function shouldn't perform any logic, just translate the args
// to PigeonOptions. Synthesized values inside of the PigeonOption should
// get set in the `run` function to accomodate users that are using the
// `configurePigeon` function.
final ArgResults results = _argParser.parse(args);
final PigeonOptions opts = PigeonOptions();
@ -334,9 +339,6 @@ options:
);
opts.javaOut = results['java_out'];
opts.javaOptions = JavaOptions(
className: (opts.javaOut == null)
? null
: path.basenameWithoutExtension(opts.javaOut!),
package: results['java_package'],
);
opts.dartOptions = DartOptions()..isNullSafe = results['dart_null_safety'];
@ -480,6 +482,10 @@ options:
options.objcOptions ?? ObjcOptions(), parseResults.root, sink));
}
if (options.javaOut != null) {
if (options.javaOptions!.className == null) {
options.javaOptions!.className =
path.basenameWithoutExtension(options.javaOut!);
}
await _runGenerator(
options.javaOut!,
(StringSink sink) => generateJava(

View File

@ -54,6 +54,7 @@ test_pigeon_ios() {
temp_dir=$(mktmpdir)
pub run pigeon \
--no-dart_null_safety \
--input $1 \
--dart_out $temp_dir/pigeon.dart \
--objc_header_out $temp_dir/pigeon.h \
@ -80,7 +81,6 @@ test_pigeon_android() {
pub run pigeon \
--input $1 \
--dart_null_safety \
--dart_out $temp_dir/pigeon.dart \
--java_out $temp_dir/Pigeon.java \
--java_package foo
@ -113,7 +113,6 @@ test_null_safe_dart() {
pub run pigeon \
--input $1 \
--dart_null_safety \
--dart_out $temp_dir/pigeon.dart
dartanalyzer $temp_dir/pigeon.dart --fatal-infos --fatal-warnings --packages ./e2e_tests/test_objc/.packages
@ -165,7 +164,6 @@ pub run pigeon 1> /dev/null
pushd $PWD
pub run pigeon \
--input pigeons/message.dart \
--dart_null_safety \
--dart_out platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart
cd platform_tests/flutter_null_safe_unit_tests
flutter pub get
@ -178,7 +176,6 @@ popd
pushd $PWD
pub run pigeon \
--input pigeons/message.dart \
--dart_null_safety \
--dart_out mock_handler_tester/test/message.dart \
--dart_test_out mock_handler_tester/test/test.dart
dartfmt -w mock_handler_tester/test/message.dart
@ -221,11 +218,13 @@ test_pigeon_ios ./pigeons/all_datatypes.dart
# iOS unit tests on generated code.
###############################################################################
pub run pigeon \
--no-dart_null_safety \
--input pigeons/message.dart \
--dart_out /dev/null \
--objc_header_out platform_tests/ios_unit_tests/ios/Runner/messages.h \
--objc_source_out platform_tests/ios_unit_tests/ios/Runner/messages.m
pub run pigeon \
--no-dart_null_safety \
--input pigeons/async_handlers.dart \
--dart_out /dev/null \
--objc_header_out platform_tests/ios_unit_tests/ios/Runner/async_handlers.h \
@ -255,7 +254,6 @@ DARTLE_DART="e2e_tests/test_objc/lib/dartle.dart"
PIGEON_JAVA="e2e_tests/test_objc/android/app/src/main/java/io/flutter/plugins/Pigeon.java"
pub run pigeon \
--input pigeons/message.dart \
--dart_null_safety \
--dart_out $DARTLE_DART \
--objc_header_out $DARTLE_H \
--objc_source_out $DARTLE_M \

View File

@ -23,7 +23,7 @@ void main() {
classes: <Class>[klass],
);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('class Foobar'));
expect(code, contains(' dataType1 field1;'));
@ -48,7 +48,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')])
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('class Api'));
expect(code, matches('Output.*doSomething.*Input'));
@ -66,7 +66,7 @@ void main() {
)
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(
code,
@ -101,7 +101,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')])
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('abstract class Api'));
expect(code, contains('static void setup(Api'));
@ -123,7 +123,7 @@ void main() {
fields: <Field>[Field(name: 'input', dataType: 'String')]),
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('Future<void> doSomething'));
expect(code, contains('// noop'));
@ -145,7 +145,7 @@ void main() {
fields: <Field>[Field(name: 'input', dataType: 'String')]),
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
// The next line verifies that we're not setting a variable to the value of "doSomething", but
// ignores the line where we assert the value of the argument isn't null, since on that line
@ -171,7 +171,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')]),
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, matches('output.*=.*doSomething[(][)]'));
expect(code, contains('Output doSomething();'));
@ -193,7 +193,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')]),
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, matches('channel.send[(]null[)]'));
});
@ -228,7 +228,7 @@ void main() {
]);
final StringBuffer mainCodeSink = StringBuffer();
final StringBuffer testCodeSink = StringBuffer();
generateDart(DartOptions(), root, mainCodeSink);
generateDart(DartOptions(isNullSafe: false), root, mainCodeSink);
final String mainCode = mainCodeSink.toString();
expect(mainCode, isNot(contains('import \'fo\\\'o.dart\';')));
expect(mainCode, contains('class Api {'));
@ -236,7 +236,8 @@ void main() {
expect(mainCode, isNot(contains('.ApiMock.doSomething')));
expect(mainCode, isNot(contains('\'${Keys.result}\': output.encode()')));
expect(mainCode, isNot(contains('return <Object, Object>{};')));
generateTestDart(DartOptions(), root, testCodeSink, "fo'o.dart");
generateTestDart(
DartOptions(isNullSafe: false), root, testCodeSink, "fo'o.dart");
final String testCode = testCodeSink.toString();
expect(testCode, contains('import \'fo\\\'o.dart\';'));
expect(testCode, isNot(contains('class Api {')));
@ -261,7 +262,7 @@ void main() {
classes: <Class>[klass],
);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('// @dart = 2.8'));
});
@ -285,7 +286,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')])
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('abstract class Api'));
expect(code, contains('Future<Output> doSomething(Input arg);'));
@ -312,7 +313,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')])
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, isNot(matches('=.s*doSomething')));
expect(code, contains('await api.doSomething('));
@ -338,7 +339,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')])
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, contains('class Api'));
expect(code, matches('Output.*doSomething.*Input'));
@ -360,7 +361,7 @@ void main() {
fields: <Field>[Field(name: 'output', dataType: 'String')]),
]);
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
generateDart(DartOptions(isNullSafe: false), root, sink);
final String code = sink.toString();
expect(code, matches('channel.send[(]null[)]'));
});