diff --git a/.codex/skills/prepare-release/SKILL.md b/.codex/skills/prepare-release/SKILL.md new file mode 100644 index 00000000..dda8de83 --- /dev/null +++ b/.codex/skills/prepare-release/SKILL.md @@ -0,0 +1,20 @@ +--- +name: prepare-release +description: Use when asked to prepare new serious_python release by bumping versions and author release notes. +--- + +## Inputs + +* Previous serious_python version from repo tags. +* Whether it's minor or major release. + +## Steps + +* Take latest serious_python release version from the repo and + increment third (patch) digit to get the next version if it's a minor release + or second (minor) digit if it's a major release. +* Set new version in pubspec.yaml of all packages in /src. +* Set new s.version in src/serious_python_darwin/darwin/serious_python_darwin.podspec. +* Set new version in src/serious_python_android/android/build.gradle. +* Run pub get for all apps in src/serious_python/example to refresh their pubspec.lock with new version. +* Add a new entry into all packages' CHANGELOG.md from a git log since the last release. Do not add chore/trivial/duplicate items, add items with related issue or PR. diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 6a5cb2e8..5cf7ce86 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python/example/flask_example/pubspec.lock b/src/serious_python/example/flask_example/pubspec.lock index abbca891..bb9c806b 100644 --- a/src/serious_python/example/flask_example/pubspec.lock +++ b/src/serious_python/example/flask_example/pubspec.lock @@ -289,42 +289,42 @@ packages: path: "../.." relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "0.9.9" + version: "0.9.10" shelf: dependency: transitive description: diff --git a/src/serious_python/example/flet_example/pubspec.lock b/src/serious_python/example/flet_example/pubspec.lock index eacde972..9984d911 100644 --- a/src/serious_python/example/flet_example/pubspec.lock +++ b/src/serious_python/example/flet_example/pubspec.lock @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -280,10 +280,10 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" js: dependency: transitive description: @@ -304,26 +304,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -368,10 +368,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" package_info_plus: dependency: "direct main" description: @@ -562,42 +562,42 @@ packages: path: "../.." relative: true source: path - version: "0.9.8" + version: "0.9.10" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "0.9.8" + version: "0.9.10" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "0.9.8" + version: "0.9.10" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "0.9.8" + version: "0.9.10" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "0.9.8" + version: "0.9.10" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "0.9.8" + version: "0.9.10" shared_preferences: dependency: transitive description: @@ -719,10 +719,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.7" toml: dependency: transitive description: @@ -839,10 +839,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -924,5 +924,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.7.0 <4.0.0" + dart: ">=3.8.0-0 <4.0.0" flutter: ">=3.22.0" diff --git a/src/serious_python/example/run_example/pubspec.lock b/src/serious_python/example/run_example/pubspec.lock index d6dc6e51..2c2d42b1 100644 --- a/src/serious_python/example/run_example/pubspec.lock +++ b/src/serious_python/example/run_example/pubspec.lock @@ -312,42 +312,42 @@ packages: path: "../.." relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "0.9.9" + version: "0.9.10" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "0.9.9" + version: "0.9.10" shelf: dependency: transitive description: diff --git a/src/serious_python/pubspec.yaml b/src/serious_python/pubspec.yaml index ba8975a4..0fb9d9cb 100644 --- a/src/serious_python/pubspec.yaml +++ b/src/serious_python/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python description: A cross-platform plugin for adding embedded Python runtime to your Flutter apps. homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 platforms: ios: diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 00985cb6..43d2f056 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index d69650a2..76284d09 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -1,5 +1,5 @@ group 'com.flet.serious_python_android' -version '0.9.9' +version '0.9.10' def python_version = '3.12' diff --git a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java index dcced8db..1f573921 100644 --- a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java +++ b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java @@ -60,6 +60,17 @@ public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBi public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { if (call.method.equals("getPlatformVersion")) { result.success("Android " + android.os.Build.VERSION.RELEASE); + } else if (call.method.equals("getAppVersion")) { + try { + String packageName = context.getPackageName(); + android.content.pm.PackageManager pm = context.getPackageManager(); + android.content.pm.PackageInfo info = pm.getPackageInfo(packageName, 0); + String versionName = info.versionName; + long versionCode = info.getLongVersionCode(); + result.success(versionName + "+" + versionCode); + } catch (Exception e) { + result.error("Error", e.getMessage(), null); + } } else if (call.method.equals("getNativeLibraryDir")) { ContextWrapper contextWrapper = new ContextWrapper(context); String nativeLibraryDir = contextWrapper.getApplicationInfo().nativeLibraryDir; diff --git a/src/serious_python_android/lib/serious_python_android.dart b/src/serious_python_android/lib/serious_python_android.dart index 53d6089b..5ce78a06 100644 --- a/src/serious_python_android/lib/serious_python_android.dart +++ b/src/serious_python_android/lib/serious_python_android.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -47,6 +48,28 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { spDebug("Unable to load libpyjni.so library: $e"); } + const pythonSharedLib = "libpython3.12.so"; + + String? getPythonFullVersion() { + try { + final cpython = getCPython(pythonSharedLib); + final versionPtr = cpython.Py_GetVersion(); + return versionPtr.cast().toDartString(); + } catch (e) { + spDebug("Unable to read Python version for invalidation: $e"); + return null; + } + } + + Future getAppVersion() async { + try { + return await methodChannel.invokeMethod('getAppVersion'); + } catch (e) { + spDebug("Unable to get app version for invalidation: $e"); + return null; + } + } + // unpack python bundle final nativeLibraryDir = await methodChannel.invokeMethod('getNativeLibraryDir'); @@ -58,8 +81,13 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { if (!await File(bundlePath).exists()) { throw Exception("Python bundle not found: $bundlePath"); } - var pythonLibPath = - await extractFileZip(bundlePath, targetPath: "python_bundle"); + final pythonVersion = getPythonFullVersion(); + spDebug("Python version: $pythonVersion"); + final pythonInvalidateKey = pythonVersion != null + ? "python:$pythonVersion" + : "python:$pythonSharedLib"; + var pythonLibPath = await extractFileZip(bundlePath, + targetPath: "python_bundle", invalidateKey: pythonInvalidateKey); spDebug("pythonLibPath: $pythonLibPath"); var programDirPath = p.dirname(appPath); @@ -72,8 +100,13 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { ]; if (await File(sitePackagesZipPath).exists()) { + final appVersion = await getAppVersion(); + spDebug("App version: $appVersion"); + final sitePackagesInvalidateKey = + appVersion != null ? "app:$appVersion" : null; var sitePackagesPath = await extractFileZip(sitePackagesZipPath, - targetPath: "python_site_packages"); + targetPath: "python_site_packages", + invalidateKey: sitePackagesInvalidateKey); spDebug("sitePackagesPath: $sitePackagesPath"); moduleSearchPaths.add(sitePackagesPath); } @@ -94,6 +127,6 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { } return runPythonProgramFFI( - sync ?? false, "libpython3.12.so", appPath, script ?? ""); + sync ?? false, pythonSharedLib, appPath, script ?? ""); } } diff --git a/src/serious_python_android/pubspec.yaml b/src/serious_python_android/pubspec.yaml index 445a4d24..5a4e4639 100644 --- a/src/serious_python_android/pubspec.yaml +++ b/src/serious_python_android/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_android description: Android implementation of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index 31614b39..cfa1bcd2 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index 2f1be9e6..6440c578 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin.podspec +++ b/src/serious_python_darwin/darwin/serious_python_darwin.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'serious_python_darwin' - s.version = '0.9.9' + s.version = '0.9.10' s.summary = 'A cross-platform plugin for adding embedded Python runtime to your Flutter apps.' s.description = <<-DESC A cross-platform plugin for adding embedded Python runtime to your Flutter apps. diff --git a/src/serious_python_darwin/pubspec.yaml b/src/serious_python_darwin/pubspec.yaml index bcd65a07..3bc30d6c 100644 --- a/src/serious_python_darwin/pubspec.yaml +++ b/src/serious_python_darwin/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_darwin description: iOS and macOS implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index 69f6ddba..65711fb8 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python_linux/pubspec.yaml b/src/serious_python_linux/pubspec.yaml index 8f202ec1..7a3db6f3 100644 --- a/src/serious_python_linux/pubspec.yaml +++ b/src/serious_python_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_linux description: Linux implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 environment: sdk: '>=3.1.3 <4.0.0' diff --git a/src/serious_python_platform_interface/CHANGELOG.md b/src/serious_python_platform_interface/CHANGELOG.md index d19ed9cd..c1824185 100644 --- a/src/serious_python_platform_interface/CHANGELOG.md +++ b/src/serious_python_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python_platform_interface/lib/src/utils.dart b/src/serious_python_platform_interface/lib/src/utils.dart index b84bd3a8..c5555dd4 100644 --- a/src/serious_python_platform_interface/lib/src/utils.dart +++ b/src/serious_python_platform_interface/lib/src/utils.dart @@ -8,12 +8,18 @@ import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; Future extractAssetOrFile(String path, - {bool isAsset = true, String? targetPath, bool checkHash = false}) async { + {bool isAsset = true, + String? targetPath, + bool checkHash = false, + String? invalidateKey}) async { WidgetsFlutterBinding.ensureInitialized(); final supportDir = await getApplicationSupportDirectory(); final destDir = Directory(p.join(supportDir.path, "flet", targetPath ?? p.dirname(path))); + var invalidateFile = File(p.join(destDir.path, ".invalidate")); + String existingInvalidateKey = ""; + String assetHash = ""; // read asset hash from asset try { @@ -30,18 +36,36 @@ Future extractAssetOrFile(String path, // always re-create in debug mode await destDir.delete(recursive: true); } else { - if (checkHash) { - if (await hashFile.exists()) { - destHash = (await hashFile.readAsString()).trim(); + var shouldDelete = false; + + if (invalidateKey != null) { + if (await invalidateFile.exists()) { + existingInvalidateKey = + (await invalidateFile.readAsString()).trim(); + } + if (existingInvalidateKey != invalidateKey) { + shouldDelete = true; + } + } + + if (!shouldDelete) { + if (checkHash) { + if (await hashFile.exists()) { + destHash = (await hashFile.readAsString()).trim(); + } + } + + if (assetHash != destHash || + (checkHash && assetHash == "" && destHash == "")) { + shouldDelete = true; + } else { + debugPrint("Application archive already unpacked to ${destDir.path}"); + return destDir.path; } } - if (assetHash != destHash || - (checkHash && assetHash == "" && destHash == "")) { + if (shouldDelete) { await destDir.delete(recursive: true); - } else { - debugPrint("Application archive already unpacked to ${destDir.path}"); - return destDir.path; } } } @@ -77,19 +101,34 @@ Future extractAssetOrFile(String path, await hashFile.writeAsString(assetHash); } + if (invalidateKey != null) { + debugPrint( + "Writing invalidate file: ${invalidateFile.path}, key: $invalidateKey"); + await invalidateFile.writeAsString(invalidateKey); + } + return destDir.path; } Future extractAssetZip(String assetPath, - {String? targetPath, bool checkHash = false}) async { + {String? targetPath, + bool checkHash = false, + String? invalidateKey}) async { return extractAssetOrFile(assetPath, - targetPath: targetPath, checkHash: checkHash); + targetPath: targetPath, + checkHash: checkHash, + invalidateKey: invalidateKey); } Future extractFileZip(String filePath, - {String? targetPath, bool checkHash = false}) async { + {String? targetPath, + bool checkHash = false, + String? invalidateKey}) async { return extractAssetOrFile(filePath, - isAsset: false, targetPath: targetPath, checkHash: checkHash); + isAsset: false, + targetPath: targetPath, + checkHash: checkHash, + invalidateKey: invalidateKey); } Future extractAsset(String assetPath) async { diff --git a/src/serious_python_platform_interface/pubspec.yaml b/src/serious_python_platform_interface/pubspec.yaml index 29d740f2..e7d67278 100644 --- a/src/serious_python_platform_interface/pubspec.yaml +++ b/src/serious_python_platform_interface/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_platform_interface description: A common platform interface for the serious_python plugin. homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index 5be374ac..db9ae0ef 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.10 + +* Android: Add debug logs and deduplicate FFI imports. +* Android: Invalidate extracted assets when version keys change. + ## 0.9.9 * Add zipDirectoryPosix to create POSIX-compliant app archives on Windows. diff --git a/src/serious_python_windows/pubspec.yaml b/src/serious_python_windows/pubspec.yaml index 16b2ae58..2b519c9a 100644 --- a/src/serious_python_windows/pubspec.yaml +++ b/src/serious_python_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_windows description: Windows implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 0.9.9 +version: 0.9.10 environment: sdk: '>=3.1.3 <4.0.0'