Remove hardcoded libpython binaries and add debug step
All checks were successful
build / build-linux (push) Successful in 16s

This commit is contained in:
kdusek
2025-12-07 23:15:18 +01:00
parent 308ce7768e
commit 6a1fe63684
1807 changed files with 172293 additions and 1 deletions

View File

@@ -0,0 +1,271 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
"""
Viewer for PyInstaller-generated archives.
"""
import argparse
import os
import sys
import PyInstaller.log
from PyInstaller.archive.readers import CArchiveReader, ZlibArchiveReader
try:
from argcomplete import autocomplete
except ImportError:
def autocomplete(parser):
return None
class ArchiveViewer:
def __init__(self, filename, interactive_mode, recursive_mode, brief_mode):
self.filename = filename
self.interactive_mode = interactive_mode
self.recursive_mode = recursive_mode
self.brief_mode = brief_mode
self.stack = []
# Recursive mode implies non-interactive mode
if self.recursive_mode:
self.interactive_mode = False
def main(self):
# Open top-level (initial) archive
archive = self._open_toplevel_archive(self.filename)
archive_name = os.path.basename(self.filename)
self.stack.append((archive_name, archive))
# Not-interactive mode
if not self.interactive_mode:
return self._non_interactive_processing()
# Interactive mode; show top-level archive
self._show_archive_contents(archive_name, archive)
# Interactive command processing
while True:
# Read command
try:
tokens = input('? ').split(None, 1)
except EOFError:
# Ctrl-D
print(file=sys.stderr) # Clear line.
break
# Print usage?
if not tokens:
self._print_usage()
continue
# Process
command = tokens[0].upper()
if command == 'Q':
break
elif command == 'U':
self._move_up_the_stack()
elif command == 'O':
self._open_embedded_archive(*tokens[1:])
elif command == 'X':
self._extract_file(*tokens[1:])
elif command == 'S':
archive_name, archive = self.stack[-1]
self._show_archive_contents(archive_name, archive)
else:
self._print_usage()
def _non_interactive_processing(self):
archive_count = 0
while self.stack:
archive_name, archive = self.stack.pop()
archive_count += 1
if archive_count > 1:
print("")
self._show_archive_contents(archive_name, archive)
if not self.recursive_mode:
continue
# Scan for embedded archives
if isinstance(archive, CArchiveReader):
for name, (*_, typecode) in archive.toc.items():
if typecode == 'z':
try:
embedded_archive = archive.open_embedded_archive(name)
except Exception as e:
print(f"Could not open embedded archive {name!r}: {e}", file=sys.stderr)
self.stack.append((name, embedded_archive))
def _print_usage(self):
print("U: go up one level", file=sys.stderr)
print("O <name>: open embedded archive with given name", file=sys.stderr)
print("X <name>: extract file with given name", file=sys.stderr)
print("S: list the contents of current archive again", file=sys.stderr)
print("Q: quit", file=sys.stderr)
def _move_up_the_stack(self):
if len(self.stack) > 1:
self.stack.pop()
archive_name, archive = self.stack[-1]
self._show_archive_contents(archive_name, archive)
else:
print("Already in the top archive!", file=sys.stderr)
def _open_toplevel_archive(self, filename):
if not os.path.isfile(filename):
print(f"Archive {filename} does not exist!", file=sys.stderr)
sys.exit(1)
if filename[-4:].lower() == '.pyz':
return ZlibArchiveReader(filename)
return CArchiveReader(filename)
def _open_embedded_archive(self, archive_name=None):
# Ask for name if not provided
if not archive_name:
archive_name = input('Open name? ')
archive_name = archive_name.strip()
# No name given; abort
if not archive_name:
return
# Open the embedded archive
_, parent_archive = self.stack[-1]
if not hasattr(parent_archive, 'open_embedded_archive'):
print("Archive does not support embedded archives!", file=sys.stderr)
return
try:
archive = parent_archive.open_embedded_archive(archive_name)
except Exception as e:
print(f"Could not open embedded archive {archive_name!r}: {e}", file=sys.stderr)
return
# Add to stack and display contents
self.stack.append((archive_name, archive))
self._show_archive_contents(archive_name, archive)
def _extract_file(self, name=None):
# Ask for name if not provided
if not name:
name = input('Extract name? ')
name = name.strip()
# Archive
archive_name, archive = self.stack[-1]
# Retrieve data
try:
if isinstance(archive, CArchiveReader):
data = archive.extract(name)
elif isinstance(archive, ZlibArchiveReader):
data = archive.extract(name, raw=True)
if data is None:
raise ValueError("Entry has no associated data!")
else:
raise NotImplementedError(f"Extraction from archive type {type(archive)} not implemented!")
except Exception as e:
print(f"Failed to extract data for entry {name!r} from {archive_name!r}: {e}", file=sys.stderr)
return
# Write to file
filename = input('Output filename? ')
if not filename:
print(repr(data))
else:
with open(filename, 'wb') as fp:
fp.write(data)
def _show_archive_contents(self, archive_name, archive):
if isinstance(archive, CArchiveReader):
if archive.options:
print(f"Options in {archive_name!r} (PKG/CArchive):")
for option in archive.options:
print(f" {option}")
print(f"Contents of {archive_name!r} (PKG/CArchive):")
if self.brief_mode:
for name in archive.toc.keys():
print(f" {name}")
else:
print(" position, length, uncompressed_length, is_compressed, typecode, name")
for name, (position, length, uncompressed_length, is_compressed, typecode) in archive.toc.items():
print(f" {position}, {length}, {uncompressed_length}, {is_compressed}, {typecode!r}, {name!r}")
elif isinstance(archive, ZlibArchiveReader):
print(f"Contents of {archive_name!r} (PYZ):")
if self.brief_mode:
for name in archive.toc.keys():
print(f" {name}")
else:
print(" typecode, position, length, name")
for name, (typecode, position, length) in archive.toc.items():
print(f" {typecode}, {position}, {length}, {name!r}")
else:
print(f"Contents of {name} (unknown)")
print(f"FIXME: implement content listing for archive type {type(archive)}!")
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'-l',
'--list',
default=False,
action='store_true',
dest='listing_mode',
help='List the archive contents and exit (default: %(default)s).',
)
parser.add_argument(
'-r',
'--recursive',
default=False,
action='store_true',
dest='recursive',
help='Recursively print an archive log (default: %(default)s). Implies --list.',
)
parser.add_argument(
'-b',
'--brief',
default=False,
action='store_true',
dest='brief',
help='When displaying archive contents, show only file names. (default: %(default)s).',
)
PyInstaller.log.__add_options(parser)
parser.add_argument(
'filename',
metavar='pyi_archive',
help="PyInstaller archive to process.",
)
autocomplete(parser)
args = parser.parse_args()
PyInstaller.log.__process_options(parser, args)
try:
viewer = ArchiveViewer(
filename=args.filename,
interactive_mode=not args.listing_mode,
recursive_mode=args.recursive,
brief_mode=args.brief,
)
viewer.main()
except KeyboardInterrupt:
raise SystemExit("Aborted by user.")
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,58 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
"""
Show dll dependencies of executable files or other dynamic libraries.
"""
import argparse
import glob
import PyInstaller.depend.bindepend
import PyInstaller.log
try:
from argcomplete import autocomplete
except ImportError:
def autocomplete(parser):
return None
def run():
parser = argparse.ArgumentParser()
PyInstaller.log.__add_options(parser)
parser.add_argument(
'filenames',
nargs='+',
metavar='executable-or-dynamic-library',
help="executables or dynamic libraries for which the dependencies should be shown",
)
autocomplete(parser)
args = parser.parse_args()
PyInstaller.log.__process_options(parser, args)
# Suppress all informative messages from the dependency code.
PyInstaller.log.getLogger('PyInstaller.build.bindepend').setLevel(PyInstaller.log.WARN)
try:
for input_filename_or_pattern in args.filenames:
for filename in glob.glob(input_filename_or_pattern):
print(f"{filename}:")
for lib_name, lib_path in sorted(PyInstaller.depend.bindepend.get_imports(filename)):
print(f" {lib_name} => {lib_path}")
print("")
except KeyboardInterrupt:
raise SystemExit("Aborted by user request.")
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,59 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
import argparse
import codecs
try:
from argcomplete import autocomplete
except ImportError:
def autocomplete(parser):
return None
def run():
parser = argparse.ArgumentParser(
epilog=(
'The printed output may be saved to a file, edited and used as the input for a version resource on any of '
'the executable targets in a PyInstaller .spec file.'
)
)
parser.add_argument(
'exe_file',
metavar='exe-file',
help="full pathname of a Windows executable",
)
parser.add_argument(
'out_filename',
metavar='out-filename',
nargs='?',
default='file_version_info.txt',
help="filename where the grabbed version info will be saved",
)
autocomplete(parser)
args = parser.parse_args()
try:
from PyInstaller.utils.win32 import versioninfo
info = versioninfo.read_version_info_from_executable(args.exe_file)
if not info:
raise SystemExit("ERROR: VersionInfo resource not found in exe")
with codecs.open(args.out_filename, 'w', 'utf-8') as fp:
fp.write(str(info))
print(f"Version info written to: {args.out_filename!r}")
except KeyboardInterrupt:
raise SystemExit("Aborted by user request.")
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,61 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
"""
Automatically build a spec file containing the description of the project.
"""
import argparse
import os
import PyInstaller.building.makespec
import PyInstaller.log
try:
from argcomplete import autocomplete
except ImportError:
def autocomplete(parser):
return None
def generate_parser():
p = argparse.ArgumentParser()
PyInstaller.building.makespec.__add_options(p)
PyInstaller.log.__add_options(p)
p.add_argument(
'scriptname',
nargs='+',
)
return p
def run():
p = generate_parser()
autocomplete(p)
args = p.parse_args()
PyInstaller.log.__process_options(p, args)
# Split pathex by using the path separator.
temppaths = args.pathex[:]
args.pathex = []
for p in temppaths:
args.pathex.extend(p.split(os.pathsep))
try:
name = PyInstaller.building.makespec.main(args.scriptname, **vars(args))
print('Wrote %s.' % name)
print('Now run pyinstaller.py to build the executable.')
except KeyboardInterrupt:
raise SystemExit("Aborted by user request.")
if __name__ == '__main__':
run()

View File

@@ -0,0 +1,51 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
import argparse
import os
try:
from argcomplete import autocomplete
except ImportError:
def autocomplete(parser):
return None
def run():
parser = argparse.ArgumentParser()
parser.add_argument(
'info_file',
metavar='info-file',
help="text file containing version info",
)
parser.add_argument(
'exe_file',
metavar='exe-file',
help="full pathname of a Windows executable",
)
autocomplete(parser)
args = parser.parse_args()
info_file = os.path.abspath(args.info_file)
exe_file = os.path.abspath(args.exe_file)
try:
from PyInstaller.utils.win32 import versioninfo
info = versioninfo.load_version_info_from_text_file(info_file)
versioninfo.write_version_info_to_executable(exe_file, info)
print(f"Version info written to: {exe_file!r}")
except KeyboardInterrupt:
raise SystemExit("Aborted by user request.")
if __name__ == '__main__':
run()