Skip to content
Merged
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
2 changes: 0 additions & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ for:
install:
- python --version
- cd sdk/python
- pip install certifi==2022.9.24
- pip install pdm
- pdm install

Expand All @@ -417,7 +416,6 @@ for:
install:
- python --version
- cd sdk/python
- pip install certifi==2022.9.24
- pip install --upgrade setuptools wheel twine pdm
- pdm install

Expand Down
1 change: 1 addition & 0 deletions sdk/python/flet/__pyinstaller/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
temp_bin_dir = None
17 changes: 11 additions & 6 deletions sdk/python/flet/__pyinstaller/hook-flet.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import os

# package entire "bin" folder
bin_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "bin"))
import flet.__pyinstaller.config as hook_config
from flet.__pyinstaller.utils import get_flet_bin_path

# package "bin/fletd" only
if os.getenv("PACKAGE_FLETD_ONLY"):
bin_path = os.path.join(bin_path, "fletd*")
bin_path = hook_config.temp_bin_dir
if not bin_path:
bin_path = get_flet_bin_path()

datas = [(bin_path, "flet/bin")]
if bin_path:
# package "bin/fletd" only
if os.getenv("PACKAGE_FLETD_ONLY"):
bin_path = os.path.join(bin_path, "fletd*")

datas = [(bin_path, "flet/bin")]
122 changes: 122 additions & 0 deletions sdk/python/flet/__pyinstaller/macos_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import os
import plistlib
import shutil
import subprocess
import tarfile
from pathlib import Path

from PyInstaller.building.icon import normalize_icon_type

from flet.utils import safe_tar_extractall


def unpack_app_bundle(tar_path):
bin_dir = str(Path(tar_path).parent)

with tarfile.open(tar_path, "r:gz") as tar_arch:
safe_tar_extractall(tar_arch, bin_dir)
os.remove(tar_path)

return os.path.join(bin_dir, "Flet.app")


def update_flet_view_icon(app_path, icon_path):
print("Updating Flet View icon", app_path, icon_path)

icon_file = "AppIcon.icns"

# normalize icon
normalized_icon_path = normalize_icon_type(
icon_path, ("icns",), "icns", os.getcwd()
)

# patch icon
print("Copying icons from", normalized_icon_path)
shutil.copy(
normalized_icon_path,
os.path.join(app_path, "Contents", "Resources", icon_file),
)

# update icon file name
pl = __load_info_plist(app_path)
pl["CFBundleIconFile"] = icon_file
del pl["CFBundleIconName"]
__save_info_plist(app_path, pl)


def update_flet_view_version_info(
app_path,
bundle_id,
product_name,
product_version,
copyright,
):
print("Updating Flet View plist", app_path)

pl = __load_info_plist(app_path)

if bundle_id:
pl["CFBundleIdentifier"] = bundle_id
if product_name:
pl["CFBundleName"] = product_name
pl["CFBundleDisplayName"] = product_name

# rename app bundle
new_app_path = os.path.join(Path(app_path).parent, f"{product_name}.app")
os.rename(app_path, new_app_path)
app_path = new_app_path
if product_version:
pl["CFBundleShortVersionString"] = product_version
if copyright:
pl["NSHumanReadableCopyright"] = copyright

__save_info_plist(app_path, pl)

return app_path


def assemble_app_bundle(app_path, tar_path):

# sign app bundle
print(f"Signing file {app_path}")
cmd_args = [
"codesign",
"-s",
"-",
"--force",
"--all-architectures",
"--timestamp",
"--deep",
app_path,
]
p = subprocess.run(
cmd_args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
)
if p.returncode:
raise SystemError(
f"codesign command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}"
)

# pack tar
with tarfile.open(tar_path, "w:gz") as tar:
tar.add(app_path, arcname=os.path.basename(app_path))

# cleanup
shutil.rmtree(app_path, ignore_errors=True)


def __load_info_plist(app_path):
with open(__get_plist_path(app_path), "rb") as fp:
return plistlib.load(fp)


def __save_info_plist(app_path, pl):
with open(__get_plist_path(app_path), "wb") as fp:
plistlib.dump(pl, fp)


def __get_plist_path(app_path):
return os.path.join(app_path, "Contents", "Info.plist")
25 changes: 25 additions & 0 deletions sdk/python/flet/__pyinstaller/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
import shutil
import tempfile
import uuid
from pathlib import Path


def get_flet_bin_path():
bin_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, "bin")
)
if not os.path.exists(bin_path):
return None
return bin_path


def copy_flet_bin():
bin_path = get_flet_bin_path()
if not bin_path:
return None

# create temp bin dir
temp_bin_dir = Path(tempfile.gettempdir()).joinpath(str(uuid.uuid4()))
shutil.copytree(bin_path, str(temp_bin_dir))
return str(temp_bin_dir)
106 changes: 106 additions & 0 deletions sdk/python/flet/__pyinstaller/win_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import os
import tempfile
import uuid
from pathlib import Path

import packaging.version as version
import pefile
from PyInstaller.building.icon import normalize_icon_type
from PyInstaller.compat import win32api
from PyInstaller.utils.win32.icon import IconFile, normalize_icon_type
from PyInstaller.utils.win32.versioninfo import decode


def update_flet_view_icon(exe_path, icon_path):
print("Updating Flet View icon", exe_path, icon_path)

RT_ICON = 3
RT_GROUP_ICON = 14

normalized_icon_path = normalize_icon_type(
icon_path, ("exe", "ico"), "ico", os.getcwd()
)
icon = IconFile(normalized_icon_path)
print("Copying icons from", normalized_icon_path)

hdst = win32api.BeginUpdateResource(exe_path, 0)

iconid = 1
# Each step in the following enumerate() will instantiate an IconFile object, as a result of deferred execution
# of the map() above.
i = 101
data = icon.grp_icon_dir()
data = data + icon.grp_icondir_entries(iconid)
win32api.UpdateResource(hdst, RT_GROUP_ICON, i, data, 1033)
print("Writing RT_GROUP_ICON %d resource with %d bytes", i, len(data))
for data in icon.images:
win32api.UpdateResource(hdst, RT_ICON, iconid, data, 1033)
print("Writing RT_ICON %d resource with %d bytes", iconid, len(data))
iconid = iconid + 1

win32api.EndUpdateResource(hdst, 0)


def update_flet_view_version_info(
exe_path,
product_name,
file_description,
product_version,
file_version,
company_name,
copyright,
):
print("Updating Flet View version info", exe_path)

# load versioninfo from exe
vs = decode(exe_path)

# update file version
if file_version:
pv = version.parse(file_version)
filevers = (pv.major, pv.minor, pv.micro, 0)
vs.ffi.fileVersionMS = (filevers[0] << 16) | (filevers[1] & 0xFFFF)
vs.ffi.fileVersionLS = (filevers[2] << 16) | (filevers[3] & 0xFFFF)

# update string props
for k in vs.kids[0].kids[0].kids:
if k.name == "ProductName":
k.val = product_name if product_name else ""
elif k.name == "FileDescription":
k.val = file_description if file_description else ""
if k.name == "ProductVersion":
k.val = product_version if product_version else ""
if k.name == "FileVersion" and file_version:
k.val = file_version if file_version else ""
if k.name == "CompanyName":
k.val = company_name if company_name else ""
if k.name == "LegalCopyright":
k.val = copyright if copyright else ""

version_info_path = str(Path(tempfile.gettempdir()).joinpath(str(uuid.uuid4())))
with open(version_info_path, "w") as f:
f.write(str(vs))

# Remember overlay
pe = pefile.PE(exe_path, fast_load=True)
overlay_before = pe.get_overlay()
pe.close()

hdst = win32api.BeginUpdateResource(exe_path, 0)
win32api.UpdateResource(
hdst, pefile.RESOURCE_TYPE["RT_VERSION"], 1, vs.toRaw(), 1033
)
win32api.EndUpdateResource(hdst, 0)

if overlay_before:
# Check if the overlay is still present
pe = pefile.PE(exe_path, fast_load=True)
overlay_after = pe.get_overlay()
pe.close()

# If the update removed the overlay data, re-append it
if not overlay_after:
with open(exe_path, "ab") as exef:
exef.write(overlay_before)

return version_info_path
8 changes: 5 additions & 3 deletions sdk/python/flet/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import argparse
import sys
import flet.version

import flet.cli.commands.pack
import flet.cli.commands.run
import flet.cli.commands.build
import flet.version


# Source https://stackoverflow.com/a/26379693
def set_default_subparser(self, name, args=None, positional_args=0):
Expand Down Expand Up @@ -60,7 +62,7 @@ def main():
# sp.default = "run"

flet.cli.commands.run.Command.register_to(sp, "run")
flet.cli.commands.build.Command.register_to(sp, "build")
flet.cli.commands.pack.Command.register_to(sp, "pack")
parser.set_default_subparser("run", positional_args=1)

# print usage if called without args
Expand Down
23 changes: 0 additions & 23 deletions sdk/python/flet/cli/commands/build.py

This file was deleted.

Loading