Skip to content

Commit 27ca310

Browse files
authored
[jnigen] Add regenerate script (dart-archive/jnigen#106)
1 parent f5b33be commit 27ca310

File tree

3 files changed

+203
-129
lines changed

3 files changed

+203
-129
lines changed

pkgs/jnigen/tool/command_runner.dart

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import 'dart:io';
2+
3+
const ansiRed = '\x1b[31m';
4+
const ansiDefault = '\x1b[39;49m';
5+
6+
void printError(Object? message) {
7+
if (stderr.supportsAnsiEscapes) {
8+
message = '$ansiRed$message$ansiDefault';
9+
}
10+
stderr.writeln(message);
11+
}
12+
13+
class StepFailure implements Exception {
14+
StepFailure(this.name);
15+
String name;
16+
@override
17+
String toString() => 'step failed: $name';
18+
}
19+
20+
abstract class Step {
21+
/// Runs this step, raises an exception if something fails.
22+
Future<void> run();
23+
}
24+
25+
class Callback implements Step {
26+
Callback(this.name, this.function);
27+
String name;
28+
Future<void> Function() function;
29+
@override
30+
Future<void> run() => function();
31+
}
32+
33+
class Command implements Step {
34+
Command(this.exec, this.args, this.workingDirectory);
35+
final String exec;
36+
final List<String> args;
37+
final Uri workingDirectory;
38+
39+
@override
40+
Future<void> run() async {
41+
final result = await Process.run(
42+
exec,
43+
args,
44+
workingDirectory: workingDirectory.toFilePath(),
45+
runInShell: true,
46+
);
47+
if (result.exitCode != 0) {
48+
printError(result.stdout);
49+
printError(result.stderr);
50+
final commandString = "$exec ${args.join(" ")}";
51+
stderr.writeln("failure executing command: $commandString");
52+
throw StepFailure(commandString);
53+
}
54+
}
55+
}
56+
57+
class Runner {
58+
static final gitRoot = getRepositoryRoot();
59+
Runner(this.name, this.defaultWorkingDir);
60+
String name;
61+
Uri defaultWorkingDir;
62+
final steps = <Step>[];
63+
final cleanupSteps = <Step>[];
64+
65+
void chainCommand(String exec, List<String> args, {Uri? workingDirectory}) =>
66+
_addCommand(steps, exec, args, workingDirectory: workingDirectory);
67+
68+
void chainCleanupCommand(String exec, List<String> args,
69+
{Uri? workingDirectory}) =>
70+
_addCommand(cleanupSteps, exec, args, workingDirectory: workingDirectory);
71+
72+
void _addCommand(List<Step> list, String exec, List<String> args,
73+
{Uri? workingDirectory}) {
74+
list.add(Command(exec, args, (workingDirectory ?? defaultWorkingDir)));
75+
}
76+
77+
void chainCallback(String name, Future<void> Function() callback) {
78+
steps.add(Callback(name, callback));
79+
}
80+
81+
Future<void> run() async {
82+
stderr.writeln("started: $name");
83+
var error = false;
84+
for (var step in steps) {
85+
try {
86+
await step.run();
87+
} on StepFailure catch (e) {
88+
stderr.writeln(e);
89+
error = true;
90+
exitCode = 1;
91+
break;
92+
}
93+
}
94+
stderr.writeln('${error ? "failed" : "complete"}: $name');
95+
for (var step in cleanupSteps) {
96+
try {
97+
await step.run();
98+
} on Exception catch (e) {
99+
printError("ERROR: $e");
100+
}
101+
}
102+
}
103+
}
104+
105+
Uri getRepositoryRoot() {
106+
final gitCommand = Process.runSync("git", ["rev-parse", "--show-toplevel"]);
107+
final output = gitCommand.stdout as String;
108+
return Uri.directory(output.trim());
109+
}

pkgs/jnigen/tool/pre_commit_checks.dart

Lines changed: 55 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -16,115 +16,26 @@
1616
import 'dart:async';
1717
import 'dart:io';
1818

19-
const ansiRed = '\x1b[31m';
20-
const ansiDefault = '\x1b[39;49m';
21-
22-
void printError(Object? message) {
23-
if (stderr.supportsAnsiEscapes) {
24-
message = '$ansiRed$message$ansiDefault';
25-
}
26-
stderr.writeln(message);
27-
}
28-
29-
class StepFailure implements Exception {
30-
StepFailure(this.name);
31-
String name;
32-
@override
33-
String toString() => 'step failed: $name';
34-
}
35-
36-
abstract class Step {
37-
/// Runs this step, raises an exception if something fails.
38-
Future<void> run();
39-
}
40-
41-
class Callback implements Step {
42-
Callback(this.name, this.function);
43-
String name;
44-
Future<void> Function() function;
45-
@override
46-
Future<void> run() => function();
47-
}
48-
49-
class Command implements Step {
50-
Command(this.exec, this.args, this.workingDirectory);
51-
final String exec;
52-
final List<String> args;
53-
final String workingDirectory;
54-
55-
@override
56-
Future<void> run() async {
57-
final result =
58-
await Process.run(exec, args, workingDirectory: workingDirectory);
59-
if (result.exitCode != 0) {
60-
printError(result.stdout);
61-
printError(result.stderr);
62-
final commandString = "$exec ${args.join(" ")}";
63-
stderr.writeln("failure executing command: $commandString");
64-
throw StepFailure(commandString);
65-
}
66-
}
67-
}
68-
69-
class Runner {
70-
static final gitRoot = getRepositoryRoot();
71-
Runner(this.name, this.defaultWorkingDir);
72-
String name;
73-
String defaultWorkingDir;
74-
final steps = <Step>[];
75-
final cleanupSteps = <Step>[];
76-
77-
void chainCommand(String exec, List<String> args,
78-
{String? workingDirectory}) =>
79-
_addCommand(steps, exec, args, workingDirectory: workingDirectory);
80-
81-
void chainCleanupCommand(String exec, List<String> args,
82-
{String? workingDirectory}) =>
83-
_addCommand(cleanupSteps, exec, args, workingDirectory: workingDirectory);
84-
85-
void _addCommand(List<Step> list, String exec, List<String> args,
86-
{String? workingDirectory}) {
87-
final resolvedWorkingDirectory =
88-
gitRoot.resolve(workingDirectory ?? defaultWorkingDir);
89-
list.add(Command(exec, args, resolvedWorkingDirectory.toFilePath()));
90-
}
91-
92-
void chainCallback(String name, Future<void> Function() callback) {
93-
steps.add(Callback(name, callback));
94-
}
95-
96-
Future<void> run() async {
97-
stderr.writeln("started: $name");
98-
var error = false;
99-
for (var step in steps) {
100-
try {
101-
await step.run();
102-
} on StepFailure catch (e) {
103-
stderr.writeln(e);
104-
error = true;
105-
exitCode = 1;
106-
break;
107-
}
108-
}
109-
stderr.writeln('${error ? "failed" : "complete"}: $name');
110-
for (var step in cleanupSteps) {
111-
try {
112-
await step.run();
113-
} on Exception catch (e) {
114-
printError("ERROR: $e");
115-
}
116-
}
117-
}
118-
}
119-
120-
Uri getRepositoryRoot() {
121-
final gitCommand = Process.runSync("git", ["rev-parse", "--show-toplevel"]);
122-
final output = gitCommand.stdout as String;
123-
return Uri.directory(output.trim());
124-
}
19+
import 'command_runner.dart';
12520

12621
void main() async {
127-
final jniAnalyze = Runner("Analyze JNI", "jni");
22+
final gitRoot = getRepositoryRoot();
23+
24+
// change to project root
25+
Directory.current = gitRoot.toFilePath();
26+
27+
final tempDir = Directory.current.createTempSync('jnigen_checks_clone_');
28+
final tempJniPath = tempDir.uri.resolve("jni/");
29+
final tempJnigenPath = tempDir.uri.resolve("jnigen/");
30+
final gitClone = Runner("Clone jni", Directory.current.uri)
31+
..chainCommand('git', ['clone', '.', tempDir.path])
32+
..chainCommand("flutter", ["pub", "get", "--offline"],
33+
workingDirectory: tempJniPath)
34+
..chainCommand("dart", ["pub", "get", "--offline"],
35+
workingDirectory: tempJnigenPath);
36+
await gitClone.run();
37+
38+
final jniAnalyze = Runner("Analyze JNI", tempJniPath);
12839
jniAnalyze
12940
..chainCommand("dart", ["analyze", "--fatal-infos"])
13041
..chainCommand(
@@ -139,35 +50,44 @@ void main() async {
13950
"third_party/global_jni_env.c",
14051
"third_party/global_jni_env.h",
14152
],
142-
workingDirectory: "jni/src");
143-
final jniTest = Runner("Test JNI", "jni")
53+
workingDirectory: tempJniPath.resolve("src/"));
54+
final jniTest = Runner("Test JNI", tempJniPath)
14455
..chainCommand("dart", ["run", "jni:setup"])
14556
..chainCommand("dart", ["test", "-j", "1"]);
14657
unawaited(jniAnalyze.run().then((f) => jniTest.run()));
58+
14759
final ffigenBindingsPath = getRepositoryRoot()
14860
.resolve("jni/lib/src/third_party/jni_bindings_generated.dart");
14961
final ffigenBindings = File.fromUri(ffigenBindingsPath);
15062
final oldBindingsText = ffigenBindings.readAsStringSync();
151-
final ffigenCompare = Runner("Generate & Compare FFIGEN bindings", "jni")
152-
..chainCommand("dart", ["run", "ffigen", "--config", "ffigen.yaml"])
153-
..chainCallback("compare bindings", () async {
154-
final newBindingsText = await ffigenBindings.readAsString();
155-
if (newBindingsText != oldBindingsText) {
156-
await ffigenBindings.writeAsString(oldBindingsText);
157-
throw "new JNI.h bindings differ from old bindings";
158-
}
159-
});
63+
final ffigenCompare =
64+
Runner("Generate & Compare FFIGEN bindings", tempJniPath)
65+
..chainCommand("dart", ["run", "ffigen", "--config", "ffigen.yaml"])
66+
..chainCallback("compare bindings", () async {
67+
final newBindingsText = await ffigenBindings.readAsString();
68+
if (newBindingsText != oldBindingsText) {
69+
await ffigenBindings.writeAsString(oldBindingsText);
70+
throw "new JNI.h bindings differ from old bindings";
71+
}
72+
});
16073
unawaited(ffigenCompare.run());
16174

162-
final jnigenAnalyze = Runner("Analyze jnigen", "jnigen")
75+
final jnigenAnalyze = Runner("Analyze jnigen", tempJnigenPath)
16376
..chainCommand("dart", ["analyze", "--fatal-infos"])
16477
..chainCommand(
16578
"dart", ["format", "--output=none", "--set-exit-if-changed", "."])
16679
..chainCommand("dart", ["run", "jnigen:setup"]);
167-
final jnigenTest = Runner("Test jnigen", "jnigen")
168-
..chainCommand("dart", ["test"]);
80+
81+
// Tests may need more time when running on systems with less cores.
82+
// So '--timeout 2x' is specified.
83+
final jnigenTest = Runner("Test jnigen", gitRoot.resolve("jnigen/"))
84+
..chainCommand("dart", ["test", "--timeout", "2x"]);
85+
86+
// Note: Running in_app_java and notification_plugin checks on source dir
87+
// itself, because running flutter build in cloned dir will take time.
16988
final compareInAppJavaBindings = Runner(
170-
"Generate & compare InAppJava bindings", "jnigen/example/in_app_java")
89+
"Generate & compare InAppJava bindings",
90+
gitRoot.resolve("jnigen/example/in_app_java"))
17191
..chainCommand("dart", [
17292
"run",
17393
"jnigen",
@@ -179,8 +99,9 @@ void main() async {
17999
..chainCommand("diff", ["lib/android_utils.dart", "_temp.dart"])
180100
..chainCommand("diff", ["-qr", "src/android_utils/", "src_temp/"])
181101
..chainCleanupCommand("rm", ["-r", "_temp.dart", "src_temp"]);
182-
final comparePdfboxBindings = Runner(
183-
"Generate & compare PdfBox Bindings", "jnigen/example/pdfbox_plugin")
102+
103+
final comparePdfboxBindings = Runner("Generate & compare PdfBox Bindings",
104+
gitRoot.resolve("jnigen/example/pdfbox_plugin"))
184105
..chainCommand("dart", [
185106
"run",
186107
"jnigen",
@@ -192,9 +113,10 @@ void main() async {
192113
..chainCommand("diff", ["-qr", "lib/src/third_party/", "lib_temp/"])
193114
..chainCommand("diff", ["-qr", "src/", "src_temp/"])
194115
..chainCleanupCommand("rm", ["-r", "lib_temp", "src_temp"]);
116+
195117
final compareNotificationPluginBindings = Runner(
196118
"Generate & compare NotificationPlugin Bindings",
197-
"jnigen/example/notification_plugin")
119+
gitRoot.resolve("jnigen/example/notification_plugin"))
198120
..chainCommand("dart", [
199121
"run",
200122
"jnigen",
@@ -206,10 +128,14 @@ void main() async {
206128
..chainCommand("diff", ["lib/notifications.dart", "_temp.dart"])
207129
..chainCommand("diff", ["-qr", "src/", "src_temp/"])
208130
..chainCleanupCommand("rm", ["-r", "_temp.dart", "src_temp"]);
131+
209132
unawaited(jnigenAnalyze.run().then((_) {
210-
jnigenTest.run();
211-
compareInAppJavaBindings.run();
212-
comparePdfboxBindings.run();
213-
compareNotificationPluginBindings.run();
133+
final test = jnigenTest.run();
134+
final inAppJava = compareInAppJavaBindings.run();
135+
final pdfBox = comparePdfboxBindings.run();
136+
final notificationPlugin = compareNotificationPluginBindings.run();
137+
return Future.wait([test, inAppJava, pdfBox, notificationPlugin]);
138+
}).then((_) {
139+
tempDir.deleteSync(recursive: true);
214140
}));
215141
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Run this script after any change which affects generated bindings.
6+
//
7+
// This will update all generated bindings in the whole repository.
8+
9+
import 'dart:io';
10+
11+
import 'command_runner.dart';
12+
13+
const scripts = [
14+
"test/jackson_core_test/generate.dart",
15+
"test/simple_package_test/generate.dart",
16+
];
17+
18+
const yamlBasedExamples = [
19+
"example/in_app_java",
20+
"example/pdfbox_plugin",
21+
"example/notification_plugin",
22+
];
23+
24+
void main() async {
25+
final runners = <Runner>[];
26+
final current = Directory.current.uri;
27+
for (var script in scripts) {
28+
runners.add(Runner("Run generate script: $script", current)
29+
..chainCommand("dart", ["run", script]));
30+
}
31+
32+
for (var yamlDir in yamlBasedExamples) {
33+
runners.add(
34+
Runner("Regenerate bindings in $yamlDir", current.resolve(yamlDir))
35+
..chainCommand("dart", ["run", "jnigen", "--config", "jnigen.yaml"]));
36+
}
37+
38+
await Future.wait(runners.map((runner) => runner.run()).toList());
39+
}

0 commit comments

Comments
 (0)