PyUpdater icon indicating copy to clipboard operation
PyUpdater copied to clipboard

update from app to normal executable directory on MacOS

Open hmh-the-one opened this issue 6 years ago • 4 comments

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?

hmh-the-one avatar Dec 10 '19 01:12 hmh-the-one

Hey @hmh-the-one, would you be able to provide a minimal project that reproduces the issue?

JMSwag avatar Dec 22 '19 06:12 JMSwag

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()

hmh-the-one avatar Jan 19 '20 09:01 hmh-the-one

Are hooks files and config.pyu neccessary for this issue?

hmh-the-one avatar Jan 19 '20 09:01 hmh-the-one

@hmh-the-one No, but putting everything to reproduce in a repo would be great!

JMSwag avatar Apr 18 '21 18:04 JMSwag