__main__.py
4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2021, 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)
#-----------------------------------------------------------------------------
"""
Main command-line interface to PyInstaller.
"""
import os
import argparse
import platform
from PyInstaller import __version__
from PyInstaller import log as logging
# note: don't import anything else until this function is run!
from PyInstaller.compat import check_requirements, is_conda
logger = logging.getLogger(__name__)
# Taken from https://stackoverflow.com/a/22157136 to format args more flexibly:
# any help text which beings with ``R|`` will have all newlines preserved; the
# help text will be line wrapped. See
# https://docs.python.org/3/library/argparse.html#formatter-class.
#
# This is used by the ``--debug`` option.
class _SmartFormatter(argparse.HelpFormatter):
def _split_lines(self, text, width):
if text.startswith('R|'):
# The underlying implementation of ``RawTextHelpFormatter._split_lines``
# invokes this; mimic it.
return text[2:].splitlines()
else:
# Invoke the usual formatter.
return super(_SmartFormatter, self)._split_lines(text, width)
def run_makespec(filenames, **opts):
# Split pathex by using the path separator
temppaths = opts['pathex'][:]
pathex = opts['pathex'] = []
for p in temppaths:
pathex.extend(p.split(os.pathsep))
import PyInstaller.building.makespec
spec_file = PyInstaller.building.makespec.main(filenames, **opts)
logger.info('wrote %s' % spec_file)
return spec_file
def run_build(pyi_config, spec_file, **kwargs):
import PyInstaller.building.build_main
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
def __add_options(parser):
parser.add_argument('-v', '--version', action='version',
version=__version__,
help='Show program version info and exit.')
def generate_parser() -> argparse.ArgumentParser:
"""Build an argparse parser for PyInstaller's main CLI."""
import PyInstaller.building.makespec
import PyInstaller.building.build_main
import PyInstaller.log
parser = argparse.ArgumentParser(formatter_class=_SmartFormatter)
parser.prog = "pyinstaller"
__add_options(parser)
PyInstaller.building.makespec.__add_options(parser)
PyInstaller.building.build_main.__add_options(parser)
PyInstaller.log.__add_options(parser)
parser.add_argument('filenames', metavar='scriptname', nargs='+',
help=("name of scriptfiles to be processed or "
"exactly one .spec-file. If a .spec-file is "
"specified, most options are unnecessary "
"and are ignored."))
return parser
def run(pyi_args=None, pyi_config=None):
"""
pyi_args allows running PyInstaller programatically without a subprocess
pyi_config allows checking configuration once when running multiple tests
"""
check_requirements()
import PyInstaller.log
try:
parser = generate_parser()
args = parser.parse_args(pyi_args)
PyInstaller.log.__process_options(parser, args)
# Print PyInstaller version, Python version and platform
# as the first line to stdout.
# This helps identify PyInstaller, Python and platform version
# when users report issues.
logger.info('PyInstaller: %s' % __version__)
logger.info('Python: %s%s', platform.python_version(),
" (conda)" if is_conda else "")
logger.info('Platform: %s' % platform.platform())
# Skip creating .spec when .spec file is supplied
if args.filenames[0].endswith('.spec'):
spec_file = args.filenames[0]
else:
spec_file = run_makespec(**vars(args))
run_build(pyi_config, spec_file, **vars(args))
except KeyboardInterrupt:
raise SystemExit("Aborted by user request.")
except RecursionError:
from PyInstaller import _recursion_to_deep_message
_recursion_to_deep_message.raise_with_msg()
if __name__ == '__main__':
run()