Skip to content

[jnigen] Trying to fix #2188 #2208

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkgs/jnigen/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies:

dev_dependencies:
build_runner: ^2.4.12
crypto: ^3.0.6
dart_flutter_team_lints: ^3.2.0
jni: ^0.13.0
json_serializable: ^6.8.0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.github.dart_lang.jnigen

class Operators(var value: Int) {
public class Operators(var value: Int) {
operator fun plus(op: Operators): Operators {
return Operators(value + op.value)
}
Expand Down
148 changes: 147 additions & 1 deletion pkgs/jnigen/test/test_util/bindings_test_setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
// reuse of the old JVM with old classpath if we have separate tests with
// different classpaths.

// ignore_for_file: curly_braces_in_flow_control_structures, lines_longer_than_80_chars, prefer_const_declarations, omit_local_variable_types

import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:jni/jni.dart';
import 'package:path/path.dart' hide equals;

Expand Down Expand Up @@ -42,7 +46,7 @@ Future<void> bindingsTestSetup() async {
]);

final jacksonJars = await getJarPaths(join(jacksonCoreTest, 'third_party'));

print('running mvn package:');
await runCommand(
'mvn',
['package'],
Expand All @@ -53,6 +57,148 @@ Future<void> bindingsTestSetup() async {
final kotlinTestJar =
join(kotlinTestKotlin, 'target', 'kotlin_test-jar-with-dependencies.jar');

// --- Configuration ---
final jarFilePath = kotlinTestJar;
// Path to the class file *inside* the JAR
final classPathInJar = 'com/github/dart_lang/jnigen/Operators.class';
// Temporary file for extracting the class
final tempFilePath = 'Operators.class.tmp';
// --- End Configuration ---

print('--- Starting JAR Debug ---');
print('Timestamp: ${DateTime.now()}');
print('JAR File Path: $jarFilePath');
print('Class Path in JAR: $classPathInJar');
print('');

final jarFile = File(jarFilePath);

// 1. Check JAR File Existence
print('1. Checking JAR file existence...');
final jarExists = await jarFile.exists();
print(' Exists: $jarExists');
if (!jarExists) {
print(' ERROR: JAR file not found at specified path. Aborting.');
print('--- End JAR Debug ---');
exit(1); // Exit with error
}
print('');

// 2. Check if Operators.class is listed in JAR contents
print('2. Checking if class is listed in JAR contents (using `jar tf`)...');
bool classListed = false;
try {
// Ensure 'jar' command is available in PATH
final listResult =
await Process.run('jar', ['tf', jarFilePath], runInShell: true);

if (listResult.exitCode == 0) {
final output = utf8.decode(listResult.stdout as List<int>);
if (output.contains(classPathInJar)) {
classListed = true;
print(' Class "$classPathInJar" IS listed in JAR contents.');
} else {
print(
' WARNING: Class "$classPathInJar" is NOT listed in JAR contents!');
print(
' Full `jar tf` output:\n${output.substring(0, output.length > 1000 ? 1000 : output.length)}...'); // Print first 1000 chars
}
} else {
print(
' ERROR: `jar tf` command failed with exit code ${listResult.exitCode}.');
print(' Stderr: ${utf8.decode(listResult.stderr as List<int>)}');
}
} catch (e) {
print(
' ERROR: Failed to run `jar tf`. Is `jar` (from JDK) in your PATH? Exception: $e');
}
print('');

// 3. Extract Operators.class and get its info
print('3. Attempting to extract class file using `unzip -p`...');
final tempFile = File(tempFilePath);
bool extractionAttempted = false;
bool extractionSucceeded = false;
int extractedSize = -1;
String extractedSha256 = 'N/A';

// Clean up potentially leftover temp file
if (await tempFile.exists()) {
await tempFile.delete();
}

try {
// Ensure 'unzip' command is available in PATH
// Use Process.start to pipe output to file, as `unzip -p` writes to stdout
extractionAttempted = true;
final process = await Process.start(
'unzip',
['-p', jarFilePath, classPathInJar],
runInShell: true, // May be needed depending on PATH setup
);

// Pipe stdout to the temporary file
final fileSink = tempFile.openWrite();
await process.stdout.pipe(fileSink);

// Wait for the process to exit and check code
final exitCode = await process.exitCode;

if (exitCode == 0) {
// Check if file was actually created and has content
if (await tempFile.exists() && await tempFile.length() > 0) {
extractionSucceeded = true;
print(
' Extraction via `unzip -p` seems successful (exit code 0, file created).');

// 4. Get Size
final fileStat = await tempFile.stat();
extractedSize = fileStat.size;
print(' Extracted Size: $extractedSize bytes');

// 5. Calculate Checksum
final bytes = await tempFile.readAsBytes();
final digest = sha256.convert(bytes);
extractedSha256 = digest.toString();
print(' Extracted SHA256: $extractedSha256');
} else {
print(
' WARNING: `unzip -p` exited with 0, but temp file "$tempFilePath" is missing or empty.');
if (await tempFile.exists())
await tempFile.delete(); // Clean up empty file
}
} else {
print(' ERROR: `unzip -p` command failed with exit code $exitCode.');
// Try to read stderr (might not capture much depending on how unzip fails)
// Note: Reading stderr after piping stdout might be tricky / lose data.
// Consider alternative extraction methods if this fails often.
}
} catch (e) {
print(
' ERROR: Failed to run `unzip -p`. Is `unzip` in your PATH? Exception: $e');
} finally {
// 6. Clean up temp file
if (await tempFile.exists()) {
try {
await tempFile.delete();
print(' Temporary file "$tempFilePath" deleted.');
} catch (e) {
print(
' WARNING: Failed to delete temporary file "$tempFilePath". Exception: $e');
}
}
}
print('');

print('--- Summary ---');
print('JAR Exists: $jarExists');
print('Class Listed in JAR: $classListed');
print('Extraction Attempted: $extractionAttempted');
print('Extraction Succeeded: $extractionSucceeded');
print('Extracted Size: $extractedSize bytes');
print('Extracted SHA256: $extractedSha256');
print('--- End JAR Debug ---');

if (!Platform.isAndroid) {
Jni.spawn(dylibDir: join('build', 'jni_libs'), classPath: [
jniJar,
Expand Down
Loading