update from app to normal executable directory on MacOS
version: 3.1.1
Part of spec file:
exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='mac', debug=False, bootloader_ignore_signals=False, strip=False, upx=False, console=False) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=False, upx_exclude=[], name='mac') app = BUNDLE(coll, name='xxx.app', icon='favicon.icns', bundle_identifier=None)
Most of the options use default values.
After I run the first version of the xxx.app, it starts to download updates to data_dir, and then it deletes the xxx.app directory move the update directory to the app directory and extracts, what is left now is just a xxx directory now , pyupdater then try to execute a "normal" directory and of course it fails. Pyupdater doesn't rebuild mac app directory structure nor replace the MacOS directory instead. Is that anything wrong with my configuration or is it just designed to be like this?
Hey @hmh-the-one, would you be able to provide a minimal project that reproduces the issue?
My whole updater.spec is as follow(anonymous app name), and I think a simple "hello world" test.py would reproduce this issue, it has no business with the app conent. In my case , it's a cefpython app actually.
a = Analysis(['test.py'],
pathex=['.'],
binaries=[],
datas=[('favicon.png', '.')],
hiddenimports=[],
hookspath=['.'],
runtime_hooks=[],
excludes=['keypack.pyu'],
win_no_prefer_redirects=True,
win_private_assemblies=True,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='mac',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='mac')
app = BUNDLE(coll,
name='test.app',
icon='favicon.icns',
bundle_identifier=None)
And the code changes bellow(pyupdater/client/updates.py) solve my problem:
def _overwrite(self):
# Unix: Overwrites the running applications binary
mac_app_dir = None
app_parent_dir = None
if get_system() == "mac":
if self._current_app_dir.endswith("MacOS") is True:
mac_app_dir = self._current_app_dir
from pathlib import Path
app_parent_dir = Path(mac_app_dir).parent
log.debug("Looks like we're dealing with a Mac Gui")
temp_dir = get_mac_dot_app_dir(self._current_app_dir)
self._current_app_dir = temp_dir
app_update = os.path.join(self.update_folder, self.name)
# Must be dealing with Mac .app application
if not os.path.exists(app_update) and sys.platform == "darwin":
app_update += ".app"
log.debug("Update Location:\n%s", os.path.dirname(app_update))
log.debug("Update Name: %s", os.path.basename(app_update))
current_app = os.path.join(self._current_app_dir, self.name)
# Must be dealing with Mac .app application
if not os.path.exists(current_app):
current_app += ".app"
log.debug("Current App location:\n\n%s", current_app)
# Remove current app to prevent errors when moving
# update to new location
# if update_app is a directory, then we are updating a directory
if mac_app_dir:
current_app = mac_app_dir
log.debug("remove directory:\n%s", current_app)
if os.path.isdir(app_update):
if os.path.isdir(current_app):
shutil.rmtree(current_app)
else:
shutil.rmtree(os.path.dirname(current_app))
if os.path.exists(current_app):
remove_any(current_app)
if mac_app_dir:
log.debug("Moving app to new location:\n\n%s", mac_app_dir)
shutil.move(app_update, app_parent_dir)
os.rename(os.path.join(app_parent_dir, self.name), mac_app_dir)
os.rename(os.path.join(mac_app_dir, self.name), os.path.join(mac_app_dir, 'mac'))
else:
log.debug("Moving app to new location:\n\n%s", self._current_app_dir)
shutil.move(app_update, self._current_app_dir)
def _restart(self):
log.debug("Restarting")
current_app = os.path.join(self._current_app_dir, self.name)
if get_system() == "mac":
# Must be dealing with Mac .app application
if not os.path.exists(current_app):
log.debug("Must be a .app bundle")
current_app += ".app"
# mac_app_binary_dir = os.path.join(current_app, "Contents", "MacOS")
# _file = os.listdir(mac_app_binary_dir)
#
# # We are making an assumption here that only 1
# # executable will be in the MacOS folder.
# current_app = os.path.join(mac_app_binary_dir, sys.executable)
r = Restarter(current_app, name=self.name)
r.process()
Are hooks files and config.pyu neccessary for this issue?
@hmh-the-one No, but putting everything to reproduce in a repo would be great!