PyUpdater
An autoupdate framework for pyinstaller that enables simple, secure & efficient shipment of app updates.
If you think PyUpdater is awesome, please give this issue an up vote on awesome-python.
Category: Python / Distribution |
Watchers: 15 |
Star: 438 |
Fork: 77 |
Last update: Feb 1, 2023 |
If you think PyUpdater is awesome, please give this issue an up vote on awesome-python.
Hey All,
v4 was a cluster of my own making. Essentially not giving the project enough of my time. My sinceriest apologies. There is some good news though. I've finally got over my fear of front end development and have been learning quiet a lot in that area and have some cool projects under my belt. I finally feel like a half way complete developer. 😅
I initially wrote this project while learning how to code. Shotly after going though learn python the hard way. Shout out to Zed Shaw.
Lots of thinks I'd like to improve on.
PyUpdater v5 will be a clean break, saving the good stuff. Thinking in the since of a toolkit where parts are easily replaced.
Gaols
Questions / Comments / Concerns are very welccome.
Hey there, First off, thanks so much for PyUpdater, it's a much-needed package in the python ecosystem and has been immensely useful in my own projects!
This patch should address an issue in windows, when the user has installed the .exe
in a privileged folder (e.g. C://Program Files
aka #35) and the update fails silently.
It should prompt the user for access.
I need to do some testing to verify this works on my end and will update this PR with functional proof.
After building and deploying the application, upon an update, the application fails to reload, either using extract_restart()
or extract_overwrite()
. Specially on restart, it renders these errors:
./MaxPy
{}
{}
{}
(1, 1, u'downloading')
(1, 1, u'finished')
sh: 0: getcwd() failed: No such file or directory
{}
{}
Traceback (most recent call last):
File "maxpy_apploader.py", line 1299, in <module>
File "pyupdater/client/__init__.py", line 123, in __init__
File "pyupdater/client/__init__.py", line 206, in init_app
File "pyupdater/client/__init__.py", line 212, in refresh
File "pyupdater/client/__init__.py", line 469, in _get_update_manifest
File "pyupdater/client/__init__.py", line 381, in _get_manifest_from_disk
File "dsdev_utils/paths.py", line 95, in __init__
OSError: [Errno 2] No such file or directory
[18633] Failed to execute script maxpy_apploader
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
[24/01/18 15:44:22 MainProcess DEBUG] VERSION: 1.0.15
[24/01/18 15:44:22 MainProcess DEBUG] Setting up directories...
[24/01/18 15:44:22 MainProcess DEBUG] Downloading key file
[24/01/18 15:44:22 MainProcess DEBUG] Url for request: http://127.0.0.1:5000/keys.gz
[24/01/18 15:44:22 MainProcess DEBUG] Resource URL: http://127.0.0.1:5000/keys.gz
[24/01/18 15:44:22 MainProcess DEBUG] Got content length of: 181
[24/01/18 15:44:22 MainProcess DEBUG] Block size: 360
[24/01/18 15:44:22 MainProcess DEBUG] {u'status': u'downloading', u'downloaded': 181, u'total': 181, u'percent_complete': u'100.0', u'time': u'--:--'}
[24/01/18 15:44:22 MainProcess DEBUG] {u'status': u'finished', u'downloaded': 181, u'total': 181, u'percent_complete': u'100.0', u'time': u'00:00'}
[24/01/18 15:44:22 MainProcess DEBUG] Download Complete
[24/01/18 15:44:22 MainProcess DEBUG] No hash to verify
[24/01/18 15:44:22 MainProcess DEBUG] Key file download successful
[24/01/18 15:44:22 MainProcess DEBUG] Version file download failed
[24/01/18 15:44:22 MainProcess DEBUG] [Errno 2] No such file or directory
Traceback (most recent call last):
File "pyupdater/client/__init__.py", line 446, in _get_key_data
File "pyupdater/client/__init__.py", line 456, in _write_manifest_2_filesystem
File "dsdev_utils/paths.py", line 95, in __init__
OSError: [Errno 2] No such file or directory
[24/01/18 15:44:22 MainProcess DEBUG] Loading version file...
[24/01/18 15:44:22 MainProcess DEBUG] Downloading online version file
[24/01/18 15:44:22 MainProcess DEBUG] Url for request: http://127.0.0.1:5000/versions.gz
[24/01/18 15:44:22 MainProcess DEBUG] Resource URL: http://127.0.0.1:5000/versions.gz
[24/01/18 15:44:22 MainProcess DEBUG] Got content length of: 852
[24/01/18 15:44:22 MainProcess DEBUG] Block size: 1702
[24/01/18 15:44:22 MainProcess DEBUG] {u'status': u'downloading', u'downloaded': 852, u'total': 852, u'percent_complete': u'100.0', u'time': u'--:--'}
[24/01/18 15:44:22 MainProcess DEBUG] {u'status': u'finished', u'downloaded': 852, u'total': 852, u'percent_complete': u'100.0', u'time': u'00:00'}
[24/01/18 15:44:22 MainProcess DEBUG] Download Complete
[24/01/18 15:44:22 MainProcess DEBUG] No hash to verify
[24/01/18 15:44:22 MainProcess DEBUG] Version file download successful
[24/01/18 15:44:22 MainProcess DEBUG] Version file download failed
[24/01/18 15:44:22 MainProcess DEBUG] [Errno 2] No such file or directory
Traceback (most recent call last):
File "pyupdater/client/__init__.py", line 425, in _get_manifest_from_http
File "pyupdater/client/__init__.py", line 456, in _write_manifest_2_filesystem
File "dsdev_utils/paths.py", line 95, in __init__
OSError: [Errno 2] No such file or directory
Similar errors occur on overwrite.
[24/01/18 16:27:11 MainProcess DEBUG] Download Complete
[24/01/18 16:27:11 MainProcess DEBUG] Checking file hash
[24/01/18 16:27:11 MainProcess DEBUG] Update hash: f3877879848b12a9265590129ea05d1d2f7dfd0e5be8647117cf89aa99af3187
[24/01/18 16:27:11 MainProcess DEBUG] File hash verified
[24/01/18 16:27:11 MainProcess DEBUG] Applying patches
[24/01/18 16:27:11 MainProcess DEBUG] Applied patch successfully
[24/01/18 16:27:11 MainProcess DEBUG] Writing update to disk
[24/01/18 16:27:11 MainProcess DEBUG] Wrote update file
[24/01/18 16:27:11 MainProcess DEBUG] Current Info - Filename: MaxPy-nix64-1.0.16.tar.gz
[24/01/18 16:27:11 MainProcess DEBUG] Current Info - File hash: c90e684b418fe72daa4d1046f7bdea6a7bdc9846c64bb0b3cf19253f3fd3a21f
[24/01/18 16:27:11 MainProcess DEBUG] Current Info - File size: 11826776
[24/01/18 16:27:11 MainProcess DEBUG] checking file hash match
[24/01/18 16:27:11 MainProcess DEBUG] Patch download successful
[24/01/18 16:27:11 MainProcess DEBUG] Hash for binary data: c90e684b418fe72daa4d1046f7bdea6a7bdc9846c64bb0b3cf19253f3fd3a21f
[24/01/18 16:27:11 MainProcess WARNING] Update downloaded, overwriting...
[24/01/18 16:27:11 MainProcess DEBUG] Hash for binary data: c90e684b418fe72daa4d1046f7bdea6a7bdc9846c64bb0b3cf19253f3fd3a21f
[24/01/18 16:27:11 MainProcess DEBUG] Extracting Update
[24/01/18 16:27:11 MainProcess DEBUG] Update Location:
/home/eullerborges/.local/share/MaxPy/update
[24/01/18 16:27:11 MainProcess DEBUG] Update Name: MaxPy
[24/01/18 16:27:11 MainProcess DEBUG] Current App location:
/home/eullerborges/MaxPy/MaxPy
[24/01/18 16:27:11 MainProcess DEBUG] Moving app to new location:
/home/eullerborges/MaxPy
[24/01/18 16:27:11 MainProcess DEBUG] Restarting
[24/01/18 16:27:11 MainProcess DEBUG] Current App: /home/eullerborges/MaxPy/MaxPy
Hi.
I'm using PyUpdater to provide updates for my applications both on windows and on mac, but when my code, applies an update on the mac side, it just goes busy and hang, but on windows it works fine and restarts and everything.
Systems that my code are tested on.
^^ updater_client = Client(ClientConfig()) updater_client.refresh() progress_bar = wx.ProgressDialog(_("VisCon Updater"), _("Downloading update. Please wait!"), 100, None, wx.PD_APP_MODAL|wx.PD_AUTO_HIDE|wx.PD_ELAPSED_TIME|wx.PD_ESTIMATED_TIME|wx.PD_REMAINING_TIME) updater_client.add_progress_hook(lambda info: update_bar(info, progress_bar)) app_update = updater_client.update_check(variables.app_name, variables.version, variables.release_channel) if app_update is not None: variables.update_in_progress = True logging.debug("Update found.") logging.info("Updating VisCon.") logging.debug("Cleaning up old updates.") app_update.cleanup() logging.debug("cleanup done.") t = threading.Thread(daemon=True, target=download_update, args=(app_update, progress_bar,)) t.start() progress_bar.ShowModal()
def update_bar(info, bar): x = info.get(u'downloaded')/info.get(u'total')*100 wx.CallAfter(bar.Update, x)
def download_update(app_update, dialog): logging.info("Downloading update-package.") app_update.download(background=True) while app_update.is_downloaded() == False: pass logging.debug("Download done, removing progress bar.") wx.CallAfter(dialog.Destroy) logging.info("Preparing for update.") wx.CallAfter(wx.GetTopLevelWindows()[0].Close) logging.info("Executing update.") app_update.extract_restart() ``
Looking at #30 I have also tried to change the last function to: `` def download_update(app_update, dialog): logging.info("Downloading update-package.") app_update.download(background=True) while app_update.is_downloaded() == False: pass logging.debug("Download done, removing progress bar.") wx.CallAfter(dialog.Destroy) logging.info("Preparing for update.") wx.CallAfter(wx.GetTopLevelWindows()[0].Close) logging.info("Executing update.") if platform.system() == "Windows": app_update.extract_restart() return else: app_update.extract_overwrite() subprocess.Popen(sys.argv[0]) sys.exit()
``
Without success (it still works fine on windows as expected).
The user presses yes to download and install the update (not included here for brevity), the progress bar pops up, and shows the progress. When the download is complete, the progress bare gets destroyed, the window(s) of the program closes and the update is applied and the program restarts (update extracted followed by program restart).
On windows it goes like described above. On mac the following happens instead.
No errors in the log output, even with unexpected errors catched with sys.excepthook.
Hope I get a fix soon (I'm going mad lol :P )
I'm using pyupdater to produce an executable on an arm docker container.
I'm giving pyupdater build --app-version 0.9 device_agent.spec
and get an error towards the end of the process:
[INFO] Building EXE from out00-EXE.toc completed successfully.
206282 DEBUG: Changing to Directory --> /build/ada/ada/pyu-data/new
206283 DEBUG: Temp Name: arm
206284 DEBUG: Appname: arm
206285 DEBUG: Version: 0.9
206286 DEBUG: starting archive
206288 DEBUG: Temp file: device-agent
206289 DEBUG: Moving back to Directory --> /build/ada/ada
[Errno 2] No such file or directory: 'arm'
206291 ERROR: [Errno 2] No such file or directory: 'arm'
[ERROR] [Errno 2] No such file or directory: 'arm'
206292 DEBUG: [Errno 2] No such file or directory: 'arm'
Traceback (most recent call last):
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/cli/__init__.py", line 108, in main
_real_main(args)
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/cli/__init__.py", line 84, in _real_main
dispatch_command(args, pyi_args)
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/cli/__init__.py", line 97, in dispatch_command
cmd(args, pyi_args)
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/cli/commands.py", line 96, in _cmd_build
builder.build()
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/builder.py", line 86, in build
self._archive(self.args, temp_name)
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/builder.py", line 231, in _archive
filename = make_archive(self.app_name, app_name, version)
File "/build/ada.venv/local/lib/python2.7/site-packages/pyupdater/utils/__init__.py", line 273, in make_archive
shutil.copytree(target, temp_file)
File "/usr/lib/python2.7/shutil.py", line 171, in copytree
names = os.listdir(src)
OSError: [Errno 2] No such file or directory: 'arm'
The executable is produced correctly, but I wanted to find out more about the error and what I can do to prevent it.
As i needed a way to update my app and is impossible to me bundle it in a single file, i did some modifications to the source code implementing the support for onedir mode. most functions didn't required any modification, just small fixes and considerations.
i did the modifications based on @beniamino38 patch: https://gist.github.com/beniamino38/6fcb742b620085de75c22de340580f96 and #16
i have only tested it on MAC, i'm going to do the windows's test this week.
BTW, also patched the downloader.py file because i wasn't getting the correct download progress.