mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-12-13 23:02:34 +00:00
[update] Replace self without launching a subprocess in windows
Closes: #335, https://github.com/ytdl-org/youtube-dl/issues/28488, https://github.com/ytdl-org/youtube-dl/issues/5810, https://github.com/ytdl-org/youtube-dl/issues/5994 In windows, a running executable cannot be replaced. So, the old updater worked by launching a batch script and then exiting, so that the batch script can replace the executable. However, this caused the above-mentioned issues. The new method takes advantage of the fact that while the executable cannot be replaced or deleted, it can still be renamed. The current update process on windows is as follows: 1. Delete `yt-dlp.exe.old` if it exists 2. Download the new version as `yt-dlp.exe.new` 3. Rename the running exe to `yt-dlp.exe.old` 4. Rename `yt-dlp.exe.new` to `yt-dlp.exe` 5. Open a shell that deletes `yt-dlp.exe.old` and terminate While we still use a subprocess, the actual update is already done before the app terminates and the batch script does not print anything to stdout/stderr. So this solves all the above issues
This commit is contained in:
parent
c19bc311cb
commit
b25522ba52
1 changed files with 21 additions and 15 deletions
|
@ -1,7 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
|
@ -147,6 +146,11 @@ def run_update(ydl):
|
|||
directory = os.path.dirname(exe)
|
||||
if not os.access(directory, os.W_OK):
|
||||
return report_error('no write permissions on %s' % directory, expected=True)
|
||||
try:
|
||||
if os.path.exists(filename + '.old'):
|
||||
os.remove(filename + '.old')
|
||||
except (IOError, OSError):
|
||||
return report_error('unable to remove the old version')
|
||||
|
||||
try:
|
||||
arch = platform.architecture()[0][:2]
|
||||
|
@ -176,22 +180,24 @@ def run_update(ydl):
|
|||
return report_error('unable to remove corrupt download')
|
||||
|
||||
try:
|
||||
bat = os.path.join(directory, 'yt-dlp-updater.cmd')
|
||||
with io.open(bat, 'w') as batfile:
|
||||
batfile.write('''
|
||||
@(
|
||||
echo.Waiting for file handle to be closed ...
|
||||
ping 127.0.0.1 -n 5 -w 1000 > NUL
|
||||
move /Y "%s.new" "%s" > NUL
|
||||
echo.Updated yt-dlp to version %s
|
||||
)
|
||||
@start /b "" cmd /c del "%%~f0"&exit /b
|
||||
''' % (exe, exe, version_id))
|
||||
|
||||
subprocess.Popen([bat]) # Continues to run in the background
|
||||
os.rename(exe, exe + '.old')
|
||||
except (IOError, OSError):
|
||||
return report_error('unable to move current version')
|
||||
try:
|
||||
os.rename(exe + '.new', exe)
|
||||
except (IOError, OSError):
|
||||
report_error('unable to overwrite current version')
|
||||
return True # Exit app
|
||||
os.rename(exe + '.old', exe)
|
||||
return
|
||||
try:
|
||||
# Continues to run in the background
|
||||
subprocess.Popen(
|
||||
'ping 127.0.0.1 -n 5 -w 1000 & del /F "%s.old"' % exe,
|
||||
shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
ydl.to_screen('Updated yt-dlp to version %s' % version_id)
|
||||
return True # Exit app
|
||||
except OSError:
|
||||
report_error('unable to delete old version')
|
||||
|
||||
# Zip unix package
|
||||
elif isinstance(globals().get('__loader__'), zipimporter):
|
||||
|
|
Loading…
Reference in a new issue