Skip to content

Commit 10be7d4

Browse files
flet build command: Copy flutter-packages, support for platform-specific dependencies (flet-dev#4667)
* Automatic registration of custom Flutter extensions * platform-specific dependencies in `tool.flet.{platform}.dependencies`
1 parent 6e878a4 commit 10be7d4

File tree

1 file changed

+68
-23
lines changed
  • sdk/python/packages/flet-cli/src/flet_cli/commands

1 file changed

+68
-23
lines changed

sdk/python/packages/flet-cli/src/flet_cli/commands/build.py

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def __init__(self, parser: argparse.ArgumentParser) -> None:
5656
self.flutter_dependencies = None
5757
self.package_app_path = None
5858
self.options = None
59-
self.pubspec = None
6059
self.template_data = None
6160
self.python_module_filename = None
6261
self.out_dir = None
@@ -69,6 +68,7 @@ def __init__(self, parser: argparse.ArgumentParser) -> None:
6968
self.verbose = False
7069
self.build_dir = None
7170
self.flutter_dir: Optional[Path] = None
71+
self.flutter_packages_dir = None
7272
self.flutter_exe = None
7373
self.skip_flutter_doctor = get_bool_env_var("FLET_CLI_SKIP_FLUTTER_DOCTOR")
7474
self.no_rich_output = get_bool_env_var("FLET_CLI_NO_RICH_OUTPUT")
@@ -553,10 +553,11 @@ def handle(self, options: argparse.Namespace) -> None:
553553
self.validate_entry_point()
554554
self.setup_template_data()
555555
self.create_flutter_project()
556-
self.load_pubspec()
556+
self.update_flutter_dependencies()
557557
self.customize_icons_and_splash_images()
558558
self.generate_icons_and_splash_screens()
559559
self.package_python_app()
560+
self.register_flutter_extensions()
560561
self.flutter_build()
561562
self.copy_build_output()
562563

@@ -614,7 +615,8 @@ def initialize_build(self):
614615
)
615616

616617
self.build_dir = self.python_app_path.joinpath("build")
617-
self.flutter_dir = Path(self.build_dir).joinpath("flutter")
618+
self.flutter_dir = self.build_dir.joinpath("flutter")
619+
self.flutter_packages_dir = self.build_dir.joinpath("flutter-packages")
618620
self.out_dir = (
619621
Path(self.options.output_dir).resolve()
620622
if self.options.output_dir
@@ -1009,52 +1011,58 @@ def create_flutter_project(self):
10091011
f"Created Flutter bootstrap project from {template_url} with ref {template_ref} {self.emojis['checkmark']}"
10101012
)
10111013

1012-
def load_pubspec(self):
1014+
def update_flutter_dependencies(self):
10131015
assert self.pubspec_path
10141016
assert self.template_data
10151017
assert self.get_pyproject
10161018
assert isinstance(self.flutter_dependencies, dict)
10171019

10181020
with open(self.pubspec_path, encoding="utf8") as f:
1019-
self.pubspec = yaml.safe_load(f)
1021+
pubspec = yaml.safe_load(f)
10201022

10211023
# merge dependencies to a dest pubspec.yaml
10221024
for k, v in self.flutter_dependencies.items():
1023-
self.pubspec["dependencies"][k] = v
1025+
pubspec["dependencies"][k] = v
10241026

1025-
self.pubspec = merge_dict(
1026-
self.pubspec, self.get_pyproject("tool.flet.flutter.pubspec") or {}
1027+
pubspec = merge_dict(
1028+
pubspec, self.get_pyproject("tool.flet.flutter.pubspec") or {}
10271029
)
10281030

10291031
# make sure project_name is not named as any of the dependencies
1030-
for dep in self.pubspec["dependencies"].keys():
1032+
for dep in pubspec["dependencies"].keys():
10311033
if dep == self.template_data["project_name"]:
10321034
self.cleanup(
10331035
1,
10341036
f"Project name cannot have the same name as one of its dependencies: {dep}. "
10351037
f"Use --project option to specify a different project name.",
10361038
)
10371039

1040+
# save pubspec.yaml
1041+
with open(self.pubspec_path, "w", encoding="utf8") as f:
1042+
yaml.dump(pubspec, f)
1043+
10381044
def customize_icons_and_splash_images(self):
10391045
assert self.package_app_path
10401046
assert self.flutter_dir
10411047
assert self.options
10421048
assert self.get_pyproject
1043-
assert self.pubspec
10441049
assert self.pubspec_path
10451050

10461051
self.status.update(
10471052
f"[bold blue]Customizing app icons and splash images {self.emojis['loading']}... "
10481053
)
1054+
1055+
with open(self.pubspec_path, encoding="utf8") as f:
1056+
pubspec = yaml.safe_load(f)
1057+
10491058
self.assets_path = self.package_app_path.joinpath("assets")
10501059
if self.assets_path.exists():
10511060
images_dir = "images"
10521061
images_path = self.flutter_dir.joinpath(images_dir)
10531062
images_path.mkdir(exist_ok=True)
10541063

10551064
def fallback_image(yaml_path: str, images: list):
1056-
assert self.pubspec
1057-
d = self.pubspec
1065+
d = pubspec
10581066
pp = yaml_path.split("/")
10591067
for p in pp[:-1]:
10601068
d = d[p]
@@ -1196,16 +1204,14 @@ def fallback_image(yaml_path: str, images: list):
11961204
"tool.flet.splash.color"
11971205
)
11981206
if splash_color:
1199-
self.pubspec["flutter_native_splash"]["color"] = splash_color
1200-
self.pubspec["flutter_native_splash"]["android_12"][
1201-
"color"
1202-
] = splash_color
1207+
pubspec["flutter_native_splash"]["color"] = splash_color
1208+
pubspec["flutter_native_splash"]["android_12"]["color"] = splash_color
12031209
splash_dark_color = self.options.splash_dark_color or self.get_pyproject(
12041210
"tool.flet.splash.dark_color"
12051211
)
12061212
if splash_dark_color:
1207-
self.pubspec["flutter_native_splash"]["color_dark"] = splash_dark_color
1208-
self.pubspec["flutter_native_splash"]["android_12"][
1213+
pubspec["flutter_native_splash"]["color_dark"] = splash_dark_color
1214+
pubspec["flutter_native_splash"]["android_12"][
12091215
"color_dark"
12101216
] = splash_dark_color
12111217

@@ -1214,12 +1220,12 @@ def fallback_image(yaml_path: str, images: list):
12141220
or self.get_pyproject("tool.flet.android.adaptive_icon_background")
12151221
)
12161222
if adaptive_icon_background:
1217-
self.pubspec["flutter_launcher_icons"][
1223+
pubspec["flutter_launcher_icons"][
12181224
"adaptive_icon_background"
12191225
] = adaptive_icon_background
12201226

12211227
# enable/disable splashes
1222-
self.pubspec["flutter_native_splash"]["web"] = (
1228+
pubspec["flutter_native_splash"]["web"] = (
12231229
not self.options.no_web_splash
12241230
if self.options.no_web_splash is not None
12251231
else (
@@ -1228,7 +1234,7 @@ def fallback_image(yaml_path: str, images: list):
12281234
else True
12291235
)
12301236
)
1231-
self.pubspec["flutter_native_splash"]["ios"] = (
1237+
pubspec["flutter_native_splash"]["ios"] = (
12321238
not self.options.no_ios_splash
12331239
if self.options.no_ios_splash is not None
12341240
else (
@@ -1237,7 +1243,7 @@ def fallback_image(yaml_path: str, images: list):
12371243
else True
12381244
)
12391245
)
1240-
self.pubspec["flutter_native_splash"]["android"] = (
1246+
pubspec["flutter_native_splash"]["android"] = (
12411247
not self.options.no_android_splash
12421248
if self.options.no_android_splash is not None
12431249
else (
@@ -1249,7 +1255,7 @@ def fallback_image(yaml_path: str, images: list):
12491255

12501256
# save pubspec.yaml
12511257
with open(self.pubspec_path, "w", encoding="utf8") as f:
1252-
yaml.dump(self.pubspec, f)
1258+
yaml.dump(pubspec, f)
12531259

12541260
console.log(
12551261
f"Customized app icons and splash images {self.emojis['checkmark']}"
@@ -1300,6 +1306,7 @@ def package_python_app(self):
13001306
assert self.package_app_path
13011307
assert self.build_dir
13021308
assert self.flutter_dir
1309+
assert self.flutter_packages_dir
13031310

13041311
self.status.update(
13051312
f"[bold blue]Packaging Python app {self.emojis['loading']}... "
@@ -1332,13 +1339,22 @@ def package_python_app(self):
13321339
) or get_project_dependencies(self.get_pyproject("project.dependencies"))
13331340

13341341
if toml_dependencies:
1342+
platform_dependencies = get_project_dependencies(
1343+
self.get_pyproject(f"tool.flet.{self.config_platform}.dependencies")
1344+
)
1345+
if platform_dependencies:
1346+
toml_dependencies.extend(platform_dependencies)
1347+
13351348
package_args.extend(
13361349
[
13371350
"--requirements",
13381351
",".join(toml_dependencies),
13391352
]
13401353
)
13411354
elif requirements_txt.exists():
1355+
if self.verbose > 1:
1356+
with open(requirements_txt, "r") as f:
1357+
console.log(f"Contents of requirements.txt: {f.read()}")
13421358
package_args.extend(["--requirements", f"-r,{requirements_txt}"])
13431359

13441360
# site-packages variable
@@ -1347,6 +1363,12 @@ def package_python_app(self):
13471363
self.build_dir / "site-packages"
13481364
)
13491365

1366+
# flutter-packages variable
1367+
if self.flutter_packages_dir.exists():
1368+
shutil.rmtree(self.flutter_packages_dir)
1369+
1370+
package_env["SERIOUS_PYTHON_FLUTTER_PACKAGES"] = str(self.flutter_packages_dir)
1371+
13501372
# exclude
13511373
exclude_list = ["build"]
13521374

@@ -1417,6 +1439,29 @@ def package_python_app(self):
14171439

14181440
console.log(f"Packaged Python app {self.emojis['checkmark']}")
14191441

1442+
def register_flutter_extensions(self):
1443+
assert self.flutter_packages_dir
1444+
assert self.pubspec_path
1445+
1446+
self.status.update(
1447+
f"[bold blue]Registering Flutter user extensions {self.emojis['loading']}... "
1448+
)
1449+
1450+
with open(self.pubspec_path, encoding="utf8") as f:
1451+
pubspec = yaml.safe_load(f)
1452+
1453+
for fp in os.listdir(self.flutter_packages_dir):
1454+
if (self.flutter_packages_dir / fp / "pubspec.yaml").exists():
1455+
pubspec["dependencies"][fp] = {
1456+
"path": str(self.flutter_packages_dir / fp)
1457+
}
1458+
1459+
# save pubspec.yaml
1460+
with open(self.pubspec_path, "w", encoding="utf8") as f:
1461+
yaml.dump(pubspec, f)
1462+
1463+
console.log(f"Registered Flutter user extensions {self.emojis['checkmark']}")
1464+
14201465
def flutter_build(self):
14211466
assert self.options
14221467
assert self.build_dir

0 commit comments

Comments
 (0)