from zipimport import zipimporter
from .compat import functools # isort: split
-from .compat import compat_realpath, compat_shlex_quote
+from .compat import compat_realpath
from .networking import Request
from .networking.exceptions import HTTPError, network_exceptions
from .utils import (
# Ref: https://en.wikipedia.org/wiki/Uname#Examples
if machine[1:] in ('x86', 'x86_64', 'amd64', 'i386', 'i686'):
machine = '_x86' if platform.architecture()[0][:2] == '32' else ''
+ # sys.executable returns a /tmp/ path for staticx builds (linux_static)
+ # Ref: https://staticx.readthedocs.io/en/latest/usage.html#run-time-information
+ if static_exe_path := os.getenv('STATICX_PROG_PATH'):
+ path = static_exe_path
return f'{remove_end(sys.platform, "32")}{machine}_exe', path
path = os.path.dirname(__file__)
**{variant: f'Auto-update is not supported for unpackaged {name} executable; Re-download the latest release'
for variant, name in {'win32_dir': 'Windows', 'darwin_dir': 'MacOS', 'linux_dir': 'Linux'}.items()},
'source': 'You cannot update when running from source code; Use git to pull the latest changes',
- 'unknown': 'You installed yt-dlp with a package manager or setup.py; Use that to update',
+ 'unknown': 'You installed yt-dlp from a manual build or with a package manager; Use that to update',
'other': 'You are using an unofficial build of yt-dlp; Build the executable again',
}
Can be created by `query_update()` or manually.
Attributes:
- tag The release tag that will be updated to. If from query_update,
- the value is after API resolution and update spec processing.
- The only property that is required.
- version The actual numeric version (if available) of the binary to be updated to,
- after API resolution and update spec processing. (default: None)
- requested_version Numeric version of the binary being requested (if available),
- after API resolution only. (default: None)
- commit Commit hash (if available) of the binary to be updated to,
- after API resolution and update spec processing. (default: None)
- This value will only match the RELEASE_GIT_HEAD of prerelease builds.
- binary_name Filename of the binary to be updated to. (default: current binary name)
- checksum Expected checksum (if available) of the binary to be
- updated to. (default: None)
+ tag The release tag that will be updated to. If from query_update,
+ the value is after API resolution and update spec processing.
+ The only property that is required.
+ version The actual numeric version (if available) of the binary to be updated to,
+ after API resolution and update spec processing. (default: None)
+ requested_version Numeric version of the binary being requested (if available),
+ after API resolution only. (default: None)
+ commit Commit hash (if available) of the binary to be updated to,
+ after API resolution and update spec processing. (default: None)
+ This value will only match the RELEASE_GIT_HEAD of prerelease builds.
+ binary_name Filename of the binary to be updated to. (default: current binary name)
+ checksum Expected checksum (if available) of the binary to be
+ updated to. (default: None)
"""
tag: str
version: str | None = None
requested_version: str | None = None
commit: str | None = None
- binary_name: str | None = _get_binary_name()
+ binary_name: str | None = _get_binary_name() # noqa: RUF009: Always returns the same value
checksum: str | None = None
_has_update = True
# XXX: use class variables to simplify testing
_channel = CHANNEL
_origin = ORIGIN
+ _update_sources = UPDATE_SOURCES
def __init__(self, ydl, target: str | None = None):
self.ydl = ydl
# For backwards compat, target needs to be treated as if it could be None
self.requested_channel, sep, self.requested_tag = (target or self._channel).rpartition('@')
# Check if requested_tag is actually the requested repo/channel
- if not sep and ('/' in self.requested_tag or self.requested_tag in UPDATE_SOURCES):
+ if not sep and ('/' in self.requested_tag or self.requested_tag in self._update_sources):
self.requested_channel = self.requested_tag
self.requested_tag: str = None # type: ignore (we set it later)
elif not self.requested_channel:
self._block_restart('Automatically restarting into custom builds is disabled for security reasons')
else:
# Check if requested_channel resolves to a known repository or else raise
- self.requested_repo = UPDATE_SOURCES.get(self.requested_channel)
+ self.requested_repo = self._update_sources.get(self.requested_channel)
if not self.requested_repo:
self._report_error(
f'Invalid update channel {self.requested_channel!r} requested. '
- f'Valid channels are {", ".join(UPDATE_SOURCES)}', True)
+ f'Valid channels are {", ".join(self._update_sources)}', True)
self._identifier = f'{detect_variant()} {system_identifier()}'
return a == b
def query_update(self, *, _output=False) -> UpdateInfo | None:
- """Fetches and returns info about the available update"""
+ """Fetches info about the available update
+ @returns An `UpdateInfo` if there is an update available, else None
+ """
if not self.requested_repo:
self._report_error('No target repository could be determined from input')
return None
has_update = False
resolved_tag = requested_version if self.requested_tag == 'latest' else self.requested_tag
- current_label = _make_label(self._origin, self._channel.partition("@")[2] or self.current_version, self.current_version)
+ current_label = _make_label(self._origin, self._channel.partition('@')[2] or self.current_version, self.current_version)
requested_label = _make_label(self.requested_repo, resolved_tag, requested_version)
latest_or_requested = f'{"Latest" if self.requested_tag == "latest" else "Requested"} version: {requested_label}'
if not has_update:
checksum=checksum)
def update(self, update_info=NO_DEFAULT):
- """Update yt-dlp executable to the latest version"""
+ """Update yt-dlp executable to the latest version
+ @param update_info `UpdateInfo | None` as returned by query_update()
+ """
if update_info is NO_DEFAULT:
update_info = self.query_update(_output=True)
if not update_info:
os.chmod(self.filename, mask)
except OSError:
return self._report_error(
- f'Unable to set permissions. Run: sudo chmod a+rx {compat_shlex_quote(self.filename)}')
+ f'Unable to set permissions. Run: sudo chmod a+rx {shell_quote(self.filename)}')
self.ydl.to_screen(f'Updated yt-dlp to {update_label}')
return True
tag = self.requested_tag
self._report_error(
f'Unable to {action}{delim} visit https://github.com/{self.requested_repo}/releases/'
- + tag if tag == "latest" else f"tag/{tag}", True)
+ + tag if tag == 'latest' else f'tag/{tag}', True)
# XXX: Everything below this line in this class is deprecated / for compat only
@property