flet-cli 1.1.0.dev2__tar.gz → 1.1.0.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/PKG-INFO +3 -3
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/pyproject.toml +3 -3
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/build_base.py +50 -11
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/flutter_base.py +1 -0
- flet_cli-1.1.0.dev3/src/flet_cli/version.py +1 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/PKG-INFO +3 -3
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/requires.txt +2 -2
- flet_cli-1.1.0.dev3/tests/test_build_package_cache.py +332 -0
- flet_cli-1.1.0.dev2/src/flet_cli/version.py +0 -1
- flet_cli-1.1.0.dev2/tests/test_build_package_cache.py +0 -103
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/README.md +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/setup.cfg +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/__init__.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/config.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/extensions.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/hook-flet.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/hook-flet_desktop.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/macos_utils.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/rthooks.dat +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/utils.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/__pyinstaller/win_utils.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/cli.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/base.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/build.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/clean.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/create.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/debug.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/devices.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/doctor.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/emulators.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/mcp.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/options.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/pack.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/publish.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/run.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/serve.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/test.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/commands/test_host.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/android.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/android_sdk.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/app_excludes.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/cli.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/distros.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/examples.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/extension_settings.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/flutter.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/hash_stamp.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/ios_sign.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/jdk.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/linux_deps.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/log_format.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/macos_sign.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/merge.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/plist.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/processes.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/project_dependencies.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/pyodide.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/pyproject_toml.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/python_versions.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli/utils/template_cache.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/SOURCES.txt +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/dependency_links.txt +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/entry_points.txt +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/src/flet_cli.egg-info/top_level.txt +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_app_excludes.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_android.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_app_path.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_copy_output.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_icons.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_ios.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_linux.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_list_options.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_macos_signing.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_platform_settings.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_splash.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_svg.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_template.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_version.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_build_windows_arm64.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_clean.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_cli_pass_through_args.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_cli_positionals.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_create.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_extension_settings.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_find_platform_image.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_flutter.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_linux_desktop_entry.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_log_format.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_macos_sign.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_pack_extensions.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_plist.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_project_dependencies.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_python_versions.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_run_assets_dir.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_run_desktop_dependency.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_run_script_args.py +0 -0
- {flet_cli-1.1.0.dev2 → flet_cli-1.1.0.dev3}/tests/test_run_watcher_unavailable.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 1.1.0.
|
|
3
|
+
Version: 1.1.0.dev3
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,8 +9,8 @@ Project-URL: Repository, https://github.com/flet-dev/flet
|
|
|
9
9
|
Project-URL: Documentation, https://flet.dev/docs
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: flet==1.1.0.
|
|
13
|
-
Requires-Dist: flet-platform-assets==1.1.0.
|
|
12
|
+
Requires-Dist: flet==1.1.0.dev3
|
|
13
|
+
Requires-Dist: flet-platform-assets==1.1.0.dev3
|
|
14
14
|
Requires-Dist: watchdog>=4.0.0
|
|
15
15
|
Requires-Dist: packaging>=25.0
|
|
16
16
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-cli"
|
|
3
|
-
version = "1.1.0.
|
|
3
|
+
version = "1.1.0.dev3"
|
|
4
4
|
description = "Flet CLI"
|
|
5
5
|
authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }]
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"flet==1.1.0.
|
|
11
|
-
"flet-platform-assets==1.1.0.
|
|
10
|
+
"flet==1.1.0.dev3",
|
|
11
|
+
"flet-platform-assets==1.1.0.dev3",
|
|
12
12
|
"watchdog >=4.0.0",
|
|
13
13
|
"packaging >=25.0",
|
|
14
14
|
"qrcode >=7.4.2",
|
|
@@ -1886,6 +1886,13 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
1886
1886
|
assert self.build_dir
|
|
1887
1887
|
assert self.pubspec_path
|
|
1888
1888
|
|
|
1889
|
+
# A deleted extension in build/flutter-packages would make this build
|
|
1890
|
+
# fail before it could reinstall it: start over with a fresh project,
|
|
1891
|
+
# fresh packages, and regenerated icons and splash images.
|
|
1892
|
+
if not second_pass and self._flutter_packages_missing():
|
|
1893
|
+
for stamp in ("template-1", "template-2", "package", "icons", "splashes"):
|
|
1894
|
+
(self.build_dir / ".hash" / stamp).unlink(missing_ok=True)
|
|
1895
|
+
|
|
1889
1896
|
hash = HashStamp(
|
|
1890
1897
|
self.build_dir / ".hash" / f"template-{'2' if second_pass else '1'}"
|
|
1891
1898
|
)
|
|
@@ -2399,6 +2406,38 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2399
2406
|
return AssetSpec(ico_sizes=sizes)
|
|
2400
2407
|
return None
|
|
2401
2408
|
|
|
2409
|
+
def _flutter_packages_missing(self) -> bool:
|
|
2410
|
+
"""
|
|
2411
|
+
Whether the Flutter project depends on an extension that is gone.
|
|
2412
|
+
|
|
2413
|
+
The previous build's `pubspec.yaml` lists the Flutter packages of the
|
|
2414
|
+
app's extensions by their path in `build/flutter-packages`. If one of
|
|
2415
|
+
them was deleted since, resolving that `pubspec.yaml` fails, and it is
|
|
2416
|
+
resolved before the packages could be installed again, so the build
|
|
2417
|
+
can't recover on its own. The build then starts over: the Flutter
|
|
2418
|
+
project is rendered again, which also restores the template's icons
|
|
2419
|
+
and splash images, so those are generated again too.
|
|
2420
|
+
|
|
2421
|
+
Returns:
|
|
2422
|
+
`True` when a dependency's path is inside `build/flutter-packages`
|
|
2423
|
+
and has no `pubspec.yaml`.
|
|
2424
|
+
"""
|
|
2425
|
+
|
|
2426
|
+
assert self.pubspec_path
|
|
2427
|
+
assert self.build_dir
|
|
2428
|
+
|
|
2429
|
+
if not os.path.exists(self.pubspec_path):
|
|
2430
|
+
return False
|
|
2431
|
+
pubspec = self.load_yaml(self.pubspec_path) or {}
|
|
2432
|
+
packages_dir = (self.build_dir / "flutter-packages").resolve()
|
|
2433
|
+
for dependency in (pubspec.get("dependencies") or {}).values():
|
|
2434
|
+
if not isinstance(dependency, dict) or "path" not in dependency:
|
|
2435
|
+
continue
|
|
2436
|
+
path = (Path(self.pubspec_path).parent / dependency["path"]).resolve()
|
|
2437
|
+
if packages_dir in path.parents and not (path / "pubspec.yaml").exists():
|
|
2438
|
+
return True
|
|
2439
|
+
return False
|
|
2440
|
+
|
|
2402
2441
|
def _site_packages_missing(self) -> bool:
|
|
2403
2442
|
"""
|
|
2404
2443
|
Whether any required platform package directory has no package files.
|
|
@@ -2947,17 +2986,17 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2947
2986
|
for arg in package_args:
|
|
2948
2987
|
hash.update(arg)
|
|
2949
2988
|
|
|
2950
|
-
if
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2989
|
+
if (
|
|
2990
|
+
not dev_packages_configured
|
|
2991
|
+
and not hash.has_changed()
|
|
2992
|
+
and not self._site_packages_missing()
|
|
2993
|
+
):
|
|
2994
|
+
package_args.append("--skip-site-packages")
|
|
2995
|
+
# serious_python skips copying Flutter packages to the temp dir
|
|
2996
|
+
# under --skip-site-packages, so register_flutter_extensions must
|
|
2997
|
+
# keep (not wipe) the permanent flutter-packages copy from the
|
|
2998
|
+
# previous build.
|
|
2999
|
+
self.site_packages_skipped = True
|
|
2961
3000
|
|
|
2962
3001
|
package_result = self.run(
|
|
2963
3002
|
package_args,
|
|
@@ -187,6 +187,7 @@ class BaseFlutterCommand(BaseCommand):
|
|
|
187
187
|
assert self.options
|
|
188
188
|
self.required_flutter_version = version.Version(flet.version.flutter_version)
|
|
189
189
|
if self.required_flutter_version == version.Version("0"):
|
|
190
|
+
self.skip_flutter_doctor = True
|
|
190
191
|
self.cleanup(
|
|
191
192
|
1,
|
|
192
193
|
"Unable to determine the required Flutter SDK version. "
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "1.1.0.dev3"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 1.1.0.
|
|
3
|
+
Version: 1.1.0.dev3
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,8 +9,8 @@ Project-URL: Repository, https://github.com/flet-dev/flet
|
|
|
9
9
|
Project-URL: Documentation, https://flet.dev/docs
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: flet==1.1.0.
|
|
13
|
-
Requires-Dist: flet-platform-assets==1.1.0.
|
|
12
|
+
Requires-Dist: flet==1.1.0.dev3
|
|
13
|
+
Requires-Dist: flet-platform-assets==1.1.0.dev3
|
|
14
14
|
Requires-Dist: watchdog>=4.0.0
|
|
15
15
|
Requires-Dist: packaging>=25.0
|
|
16
16
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"""Reuse and recovery of the packages a previous `flet build` left in build/."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from types import SimpleNamespace
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from flet_cli.cli import parse_command_line
|
|
12
|
+
from flet_cli.commands.build_base import BaseBuildCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def command(tmp_path):
|
|
17
|
+
"""A build command with its build directories under `tmp_path`."""
|
|
18
|
+
cmd = BaseBuildCommand.__new__(BaseBuildCommand)
|
|
19
|
+
cmd.build_dir = tmp_path / "build"
|
|
20
|
+
cmd.flutter_dir = cmd.build_dir / "flutter"
|
|
21
|
+
cmd.template_data = {"_options": {"target_arch": []}}
|
|
22
|
+
cmd.python_release = SimpleNamespace(android_abis=("arm64-v8a", "x86_64"))
|
|
23
|
+
return cmd
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def write_package(directory):
|
|
27
|
+
"""Add an installed `flet` package to a site-packages `directory`."""
|
|
28
|
+
package = directory / "flet" / "__init__.pyc"
|
|
29
|
+
package.parent.mkdir(parents=True, exist_ok=True)
|
|
30
|
+
package.write_bytes(b"package")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def write_pubspec(command, **extensions):
|
|
34
|
+
"""Write the Flutter project's pubspec.yaml with these path dependencies."""
|
|
35
|
+
command.pubspec_path = str(command.flutter_dir / "pubspec.yaml")
|
|
36
|
+
command.flutter_dir.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
dependencies = {"flutter": {"sdk": "flutter"}, "provider": "^6.0.0"}
|
|
38
|
+
for name, path in extensions.items():
|
|
39
|
+
dependencies[name] = {"path": str(path)}
|
|
40
|
+
Path(command.pubspec_path).write_text(
|
|
41
|
+
yaml.safe_dump({"dependencies": dependencies})
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def pubspec_dependencies(command):
|
|
46
|
+
"""Return the dependencies listed in the Flutter project's pubspec.yaml."""
|
|
47
|
+
return yaml.safe_load(Path(command.pubspec_path).read_text())["dependencies"]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def write_extension(directory, name="flet_map", version="1.0.0"):
|
|
51
|
+
"""Put a Flutter package called `name` into `directory`."""
|
|
52
|
+
extension = directory / name
|
|
53
|
+
extension.mkdir(parents=True, exist_ok=True)
|
|
54
|
+
(extension / "pubspec.yaml").write_text(f"name: {name}\nversion: {version}\n")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TestSitePackagesMissing:
|
|
58
|
+
"""`_site_packages_missing()` decides when installed packages can be reused."""
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize("platform", ["Windows", "Linux", "Darwin", "Emscripten"])
|
|
61
|
+
def test_missing_empty_and_populated_package_directory(self, command, platform):
|
|
62
|
+
"""Counts site-packages as present only once it holds package files."""
|
|
63
|
+
command.package_platform = platform
|
|
64
|
+
root = command.flutter_dir if platform == "Emscripten" else command.build_dir
|
|
65
|
+
packages = root / "site-packages"
|
|
66
|
+
if platform == "Emscripten":
|
|
67
|
+
packages = root / "build" / "site-packages"
|
|
68
|
+
# A native cache must not mask missing web packages.
|
|
69
|
+
write_package(command.build_dir / "site-packages")
|
|
70
|
+
assert command._site_packages_missing()
|
|
71
|
+
|
|
72
|
+
(packages / "flet").mkdir(parents=True)
|
|
73
|
+
assert command._site_packages_missing()
|
|
74
|
+
|
|
75
|
+
write_package(packages)
|
|
76
|
+
assert not command._site_packages_missing()
|
|
77
|
+
|
|
78
|
+
def test_darwin_pod_metadata_is_not_a_package(self, command, tmp_path):
|
|
79
|
+
"""Ignores the hidden `.pod` link serious_python leaves on Darwin."""
|
|
80
|
+
command.package_platform = "Darwin"
|
|
81
|
+
packages = command.build_dir / "site-packages"
|
|
82
|
+
packages.mkdir(parents=True)
|
|
83
|
+
pod = tmp_path / "pod"
|
|
84
|
+
pod.mkdir()
|
|
85
|
+
(pod / "sync_site_packages.sh").write_text("#!/bin/sh\n")
|
|
86
|
+
try:
|
|
87
|
+
(packages / ".pod").symlink_to(pod, target_is_directory=True)
|
|
88
|
+
except OSError:
|
|
89
|
+
pytest.skip("Creating symlinks is unavailable")
|
|
90
|
+
|
|
91
|
+
assert command._site_packages_missing()
|
|
92
|
+
|
|
93
|
+
write_package(packages)
|
|
94
|
+
assert not command._site_packages_missing()
|
|
95
|
+
|
|
96
|
+
@pytest.mark.parametrize(
|
|
97
|
+
("platform", "architectures"),
|
|
98
|
+
[
|
|
99
|
+
("Android", ("arm64-v8a", "x86_64")),
|
|
100
|
+
(
|
|
101
|
+
"iOS",
|
|
102
|
+
("iphoneos.arm64", "iphonesimulator.arm64", "iphonesimulator.x86_64"),
|
|
103
|
+
),
|
|
104
|
+
],
|
|
105
|
+
)
|
|
106
|
+
def test_every_default_mobile_architecture_needs_packages(
|
|
107
|
+
self, command, platform, architectures
|
|
108
|
+
):
|
|
109
|
+
"""Requires packages for every default mobile architecture."""
|
|
110
|
+
command.package_platform = platform
|
|
111
|
+
packages = command.build_dir / "site-packages"
|
|
112
|
+
# Unrelated root files and empty ABI directories are not a usable cache.
|
|
113
|
+
write_package(packages)
|
|
114
|
+
for arch in architectures:
|
|
115
|
+
(packages / arch).mkdir()
|
|
116
|
+
assert command._site_packages_missing()
|
|
117
|
+
|
|
118
|
+
for arch in architectures[:-1]:
|
|
119
|
+
write_package(packages / arch)
|
|
120
|
+
assert command._site_packages_missing()
|
|
121
|
+
|
|
122
|
+
write_package(packages / architectures[-1])
|
|
123
|
+
assert not command._site_packages_missing()
|
|
124
|
+
|
|
125
|
+
(packages / architectures[-1] / "flet" / "__init__.pyc").unlink()
|
|
126
|
+
assert command._site_packages_missing()
|
|
127
|
+
|
|
128
|
+
@pytest.mark.parametrize(
|
|
129
|
+
("platform", "architecture"),
|
|
130
|
+
[("Android", "arm64-v8a"), ("iOS", "iphoneos.arm64")],
|
|
131
|
+
)
|
|
132
|
+
def test_only_selected_architectures_need_packages(
|
|
133
|
+
self, command, platform, architecture
|
|
134
|
+
):
|
|
135
|
+
"""Requires packages only for the architectures chosen with `--arch`."""
|
|
136
|
+
command.package_platform = platform
|
|
137
|
+
command.template_data["_options"]["target_arch"] = [architecture]
|
|
138
|
+
write_package(command.build_dir / "site-packages" / architecture)
|
|
139
|
+
|
|
140
|
+
assert not command._site_packages_missing()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class TestFlutterPackagesMissing:
|
|
144
|
+
"""`_flutter_packages_missing()` finds extensions pubspec.yaml points to."""
|
|
145
|
+
|
|
146
|
+
@pytest.mark.parametrize("relative", [False, True])
|
|
147
|
+
def test_detects_deleted_extension(self, command, relative):
|
|
148
|
+
"""Reports an extension in build/flutter-packages until it has a package."""
|
|
149
|
+
packages = command.build_dir / "flutter-packages"
|
|
150
|
+
write_pubspec(
|
|
151
|
+
command,
|
|
152
|
+
flet_map=Path("../flutter-packages/flet_map")
|
|
153
|
+
if relative
|
|
154
|
+
else packages / "flet_map",
|
|
155
|
+
)
|
|
156
|
+
assert command._flutter_packages_missing()
|
|
157
|
+
|
|
158
|
+
(packages / "flet_map").mkdir(parents=True)
|
|
159
|
+
assert command._flutter_packages_missing()
|
|
160
|
+
|
|
161
|
+
write_extension(packages)
|
|
162
|
+
assert not command._flutter_packages_missing()
|
|
163
|
+
|
|
164
|
+
def test_detects_one_deleted_extension_among_several(self, command):
|
|
165
|
+
"""Reports a deleted extension when other extensions are still there."""
|
|
166
|
+
packages = command.build_dir / "flutter-packages"
|
|
167
|
+
write_pubspec(
|
|
168
|
+
command,
|
|
169
|
+
flet_map=packages / "flet_map",
|
|
170
|
+
flet_geolocator=packages / "flet_geolocator",
|
|
171
|
+
)
|
|
172
|
+
write_extension(packages, "flet_map")
|
|
173
|
+
assert command._flutter_packages_missing()
|
|
174
|
+
|
|
175
|
+
write_extension(packages, "flet_geolocator")
|
|
176
|
+
assert not command._flutter_packages_missing()
|
|
177
|
+
|
|
178
|
+
def test_ignores_other_dependencies(self, command, tmp_path):
|
|
179
|
+
"""Ignores a missing pubspec.yaml and path dependencies elsewhere."""
|
|
180
|
+
command.pubspec_path = str(command.flutter_dir / "pubspec.yaml")
|
|
181
|
+
assert not command._flutter_packages_missing()
|
|
182
|
+
|
|
183
|
+
write_pubspec(command, flet_map=tmp_path / "elsewhere" / "flet_map")
|
|
184
|
+
assert not command._flutter_packages_missing()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class TestMissingExtensionRecovery:
|
|
188
|
+
"""`create_flutter_project()` starting over when an extension is gone."""
|
|
189
|
+
|
|
190
|
+
@pytest.mark.parametrize("extension_deleted", [False, True])
|
|
191
|
+
def test_restarts_the_build(
|
|
192
|
+
self, command, monkeypatch, tmp_path, extension_deleted
|
|
193
|
+
):
|
|
194
|
+
"""Starts over with a clean project only when an extension is gone."""
|
|
195
|
+
import cookiecutter.main
|
|
196
|
+
|
|
197
|
+
command.options = SimpleNamespace(
|
|
198
|
+
template=str(tmp_path / "template"), template_ref=None, template_dir=None
|
|
199
|
+
)
|
|
200
|
+
command.template_data = {"project_name": "test_app"}
|
|
201
|
+
command.get_pyproject = lambda *_: None
|
|
202
|
+
command.config_platform = "web"
|
|
203
|
+
command.emojis = {"checkmark": ""}
|
|
204
|
+
command.verbose = 0
|
|
205
|
+
command.step = lambda *_: contextlib.nullcontext()
|
|
206
|
+
command.pubspec_path = str(command.flutter_dir / "pubspec.yaml")
|
|
207
|
+
# The template renders a pubspec.yaml without extensions.
|
|
208
|
+
monkeypatch.setattr(
|
|
209
|
+
cookiecutter.main, "cookiecutter", lambda **_: write_pubspec(command)
|
|
210
|
+
)
|
|
211
|
+
assert command.create_flutter_project()
|
|
212
|
+
|
|
213
|
+
# A previous build added its extension after packaging.
|
|
214
|
+
packages = command.build_dir / "flutter-packages"
|
|
215
|
+
write_extension(packages)
|
|
216
|
+
write_pubspec(command, flet_map=packages / "flet_map")
|
|
217
|
+
stamps = command.build_dir / ".hash"
|
|
218
|
+
derived = ["template-2", "package", "icons", "splashes"]
|
|
219
|
+
for stamp in derived:
|
|
220
|
+
(stamps / stamp).write_text("digest")
|
|
221
|
+
if extension_deleted:
|
|
222
|
+
shutil.rmtree(packages)
|
|
223
|
+
|
|
224
|
+
assert command.create_flutter_project() is extension_deleted
|
|
225
|
+
assert [(stamps / s).exists() for s in derived] == [not extension_deleted] * 4
|
|
226
|
+
assert ("flet_map" in pubspec_dependencies(command)) is not extension_deleted
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class TestPackagePythonApp:
|
|
230
|
+
"""`package_python_app()` keeping the previous Flutter packages."""
|
|
231
|
+
|
|
232
|
+
@pytest.fixture
|
|
233
|
+
def packaging(self, command):
|
|
234
|
+
"""Package a web app that has an extension; returns what the command saw."""
|
|
235
|
+
command.options = parse_command_line(["build", "web"])
|
|
236
|
+
command.package_platform = "Emscripten"
|
|
237
|
+
command.target_platform = "web"
|
|
238
|
+
command.config_platform = "web"
|
|
239
|
+
command.python_release = SimpleNamespace(short="3.14", android_abis=())
|
|
240
|
+
command.dart_exe = "dart"
|
|
241
|
+
command.verbose = 0
|
|
242
|
+
command.python_app_path = command.package_app_path = (
|
|
243
|
+
command.build_dir.parent / "app"
|
|
244
|
+
)
|
|
245
|
+
command.python_app_path.mkdir(parents=True)
|
|
246
|
+
command.flutter_dir.mkdir(parents=True)
|
|
247
|
+
command.flutter_packages_dir = command.build_dir / "flutter-packages"
|
|
248
|
+
command.flutter_packages_temp_dir = command.build_dir / "flutter-packages-temp"
|
|
249
|
+
command.get_pyproject = lambda *_: None
|
|
250
|
+
command.step = lambda *_: contextlib.nullcontext()
|
|
251
|
+
write_extension(command.flutter_packages_dir)
|
|
252
|
+
|
|
253
|
+
seen = {}
|
|
254
|
+
|
|
255
|
+
class Stop(Exception):
|
|
256
|
+
"""Ends the package step once the package command is reached."""
|
|
257
|
+
|
|
258
|
+
def run(args, cwd, env=None, capture_output=True):
|
|
259
|
+
"""Record the state the package command would run in, then stop."""
|
|
260
|
+
seen["flutter_packages"] = (
|
|
261
|
+
command.flutter_packages_dir / "flet_map" / "pubspec.yaml"
|
|
262
|
+
).exists()
|
|
263
|
+
seen["skip"] = "--skip-site-packages" in args
|
|
264
|
+
raise Stop
|
|
265
|
+
|
|
266
|
+
command.run = run
|
|
267
|
+
|
|
268
|
+
def package():
|
|
269
|
+
"""Run the package step up to the package command."""
|
|
270
|
+
with pytest.raises(Stop):
|
|
271
|
+
command.package_python_app()
|
|
272
|
+
return seen
|
|
273
|
+
|
|
274
|
+
return package
|
|
275
|
+
|
|
276
|
+
@pytest.mark.parametrize("previous_build", [False, True])
|
|
277
|
+
def test_reinstall_keeps_flutter_packages(self, command, packaging, previous_build):
|
|
278
|
+
"""Keeps build/flutter-packages when the package command starts."""
|
|
279
|
+
if previous_build:
|
|
280
|
+
# Packages installed by a build whose package arguments differed.
|
|
281
|
+
write_package(command.flutter_dir / "build" / "site-packages")
|
|
282
|
+
stamp = command.build_dir / ".hash" / "package"
|
|
283
|
+
stamp.parent.mkdir(parents=True)
|
|
284
|
+
stamp.write_text("previous package arguments")
|
|
285
|
+
|
|
286
|
+
assert packaging() == {"flutter_packages": True, "skip": False}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class TestRegisterFlutterExtensions:
|
|
290
|
+
"""`register_flutter_extensions()` replacing Flutter packages after packaging."""
|
|
291
|
+
|
|
292
|
+
@pytest.fixture
|
|
293
|
+
def register(self, command):
|
|
294
|
+
"""Register extensions over stale ones; returns the registered versions."""
|
|
295
|
+
command.flutter_packages_dir = command.build_dir / "flutter-packages"
|
|
296
|
+
command.flutter_packages_temp_dir = command.build_dir / "flutter-packages-temp"
|
|
297
|
+
command.flutter_dependencies = {}
|
|
298
|
+
command.template_data = {"flutter": {"dependencies": []}}
|
|
299
|
+
command.verbose = 0
|
|
300
|
+
command.emojis = {"checkmark": ""}
|
|
301
|
+
command.step = lambda *_: contextlib.nullcontext()
|
|
302
|
+
command.apply_extension_settings = lambda: None
|
|
303
|
+
write_extension(command.flutter_packages_dir, "flet_map", "1.0.0")
|
|
304
|
+
write_extension(command.flutter_packages_dir, "flet_old")
|
|
305
|
+
|
|
306
|
+
def register(skipped):
|
|
307
|
+
"""Register extensions after packaging, reused or not."""
|
|
308
|
+
command.site_packages_skipped = skipped
|
|
309
|
+
command.register_flutter_extensions()
|
|
310
|
+
return {
|
|
311
|
+
name: yaml.safe_load(
|
|
312
|
+
(Path(dependency["path"]) / "pubspec.yaml").read_text()
|
|
313
|
+
)["version"]
|
|
314
|
+
for name, dependency in command.flutter_dependencies.items()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return register
|
|
318
|
+
|
|
319
|
+
def test_reinstall_replaces_stale_extensions(self, command, register):
|
|
320
|
+
"""Replaces build/flutter-packages with the packages just installed."""
|
|
321
|
+
write_extension(command.flutter_packages_temp_dir, "flet_map", "2.0.0")
|
|
322
|
+
assert register(skipped=False) == {"flet_map": "2.0.0"}
|
|
323
|
+
assert not command.flutter_packages_temp_dir.exists()
|
|
324
|
+
|
|
325
|
+
def test_reinstall_without_extensions_removes_them(self, command, register):
|
|
326
|
+
"""Removes the previous extensions when the app no longer has any."""
|
|
327
|
+
assert register(skipped=False) == {}
|
|
328
|
+
assert not command.flutter_packages_dir.exists()
|
|
329
|
+
|
|
330
|
+
def test_skipped_install_keeps_extensions(self, register):
|
|
331
|
+
"""Keeps and registers the previous extensions when packages are reused."""
|
|
332
|
+
assert register(skipped=True) == {"flet_map": "1.0.0", "flet_old": "1.0.0"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "1.1.0.dev2"
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"""Dependency cache recovery when build artifacts have been removed."""
|
|
2
|
-
|
|
3
|
-
from types import SimpleNamespace
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
from flet_cli.commands.build_base import BaseBuildCommand
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@pytest.fixture
|
|
11
|
-
def command(tmp_path):
|
|
12
|
-
cmd = BaseBuildCommand.__new__(BaseBuildCommand)
|
|
13
|
-
cmd.build_dir = tmp_path / "build"
|
|
14
|
-
cmd.flutter_dir = cmd.build_dir / "flutter"
|
|
15
|
-
cmd.template_data = {"_options": {"target_arch": []}}
|
|
16
|
-
cmd.python_release = SimpleNamespace(android_abis=("arm64-v8a", "x86_64"))
|
|
17
|
-
return cmd
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def write_package(directory):
|
|
21
|
-
package = directory / "flet" / "__init__.pyc"
|
|
22
|
-
package.parent.mkdir(parents=True, exist_ok=True)
|
|
23
|
-
package.write_bytes(b"package")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@pytest.mark.parametrize("platform", ["Windows", "Linux", "Darwin", "Emscripten"])
|
|
27
|
-
def test_missing_empty_and_populated_package_directory(command, platform):
|
|
28
|
-
command.package_platform = platform
|
|
29
|
-
root = command.flutter_dir if platform == "Emscripten" else command.build_dir
|
|
30
|
-
packages = root / "site-packages"
|
|
31
|
-
if platform == "Emscripten":
|
|
32
|
-
packages = root / "build" / "site-packages"
|
|
33
|
-
# A native cache must not mask missing web packages.
|
|
34
|
-
write_package(command.build_dir / "site-packages")
|
|
35
|
-
assert command._site_packages_missing()
|
|
36
|
-
|
|
37
|
-
(packages / "flet").mkdir(parents=True)
|
|
38
|
-
assert command._site_packages_missing()
|
|
39
|
-
|
|
40
|
-
write_package(packages)
|
|
41
|
-
assert not command._site_packages_missing()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def test_darwin_pod_metadata_is_not_a_package(command, tmp_path):
|
|
45
|
-
command.package_platform = "Darwin"
|
|
46
|
-
packages = command.build_dir / "site-packages"
|
|
47
|
-
packages.mkdir(parents=True)
|
|
48
|
-
pod = tmp_path / "pod"
|
|
49
|
-
pod.mkdir()
|
|
50
|
-
(pod / "sync_site_packages.sh").write_text("#!/bin/sh\n")
|
|
51
|
-
try:
|
|
52
|
-
(packages / ".pod").symlink_to(pod, target_is_directory=True)
|
|
53
|
-
except OSError:
|
|
54
|
-
pytest.skip("Creating symlinks is unavailable")
|
|
55
|
-
|
|
56
|
-
assert command._site_packages_missing()
|
|
57
|
-
|
|
58
|
-
write_package(packages)
|
|
59
|
-
assert not command._site_packages_missing()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@pytest.mark.parametrize(
|
|
63
|
-
("platform", "architectures"),
|
|
64
|
-
[
|
|
65
|
-
("Android", ("arm64-v8a", "x86_64")),
|
|
66
|
-
(
|
|
67
|
-
"iOS",
|
|
68
|
-
("iphoneos.arm64", "iphonesimulator.arm64", "iphonesimulator.x86_64"),
|
|
69
|
-
),
|
|
70
|
-
],
|
|
71
|
-
)
|
|
72
|
-
def test_every_default_mobile_architecture_needs_packages(
|
|
73
|
-
command, platform, architectures
|
|
74
|
-
):
|
|
75
|
-
command.package_platform = platform
|
|
76
|
-
packages = command.build_dir / "site-packages"
|
|
77
|
-
# Unrelated root files and empty ABI directories are not a usable cache.
|
|
78
|
-
write_package(packages)
|
|
79
|
-
for arch in architectures:
|
|
80
|
-
(packages / arch).mkdir()
|
|
81
|
-
assert command._site_packages_missing()
|
|
82
|
-
|
|
83
|
-
for arch in architectures[:-1]:
|
|
84
|
-
write_package(packages / arch)
|
|
85
|
-
assert command._site_packages_missing()
|
|
86
|
-
|
|
87
|
-
write_package(packages / architectures[-1])
|
|
88
|
-
assert not command._site_packages_missing()
|
|
89
|
-
|
|
90
|
-
(packages / architectures[-1] / "flet" / "__init__.pyc").unlink()
|
|
91
|
-
assert command._site_packages_missing()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
@pytest.mark.parametrize(
|
|
95
|
-
("platform", "architecture"),
|
|
96
|
-
[("Android", "arm64-v8a"), ("iOS", "iphoneos.arm64")],
|
|
97
|
-
)
|
|
98
|
-
def test_only_selected_architectures_need_packages(command, platform, architecture):
|
|
99
|
-
command.package_platform = platform
|
|
100
|
-
command.template_data["_options"]["target_arch"] = [architecture]
|
|
101
|
-
write_package(command.build_dir / "site-packages" / architecture)
|
|
102
|
-
|
|
103
|
-
assert not command._site_packages_missing()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|