def _cache_hook_dirs(self, hook_dirs): """ Cache all hook scripts in the passed directories. Parameters ---------- hook_dirs : list List of the absolute or relative paths of all directories containing hook scripts to be cached. """ for hook_dir in hook_dirs: # Canonicalize this directory's path and validate its existence. hook_dir = os.path.abspath(expand_path(hook_dir)) if not os.path.isdir(hook_dir): raise FileNotFoundError( 'Hook directory "{}" not found.'.format(hook_dir)) # For each hook script in this directory... hook_filenames = glob.glob(os.path.join(hook_dir, 'hook-*.py')) for hook_filename in hook_filenames: # Fully-qualified name of this hook's corresponding module, # constructed by removing the "hook-" prefix and ".py" suffix. module_name = os.path.basename(hook_filename)[5:-3] if module_name in self: logger.warning("Several hooks defined for module %r. " "Please take care they do not conflict.", module_name) # Lazily loadable hook object. module_hook = ModuleHook( module_graph=self.module_graph, module_name=module_name, hook_filename=hook_filename, hook_module_name_prefix=self._hook_module_name_prefix, ) # Add this hook to this module's list of hooks. module_hooks = self.setdefault(module_name, []) module_hooks.append(module_hook)
def main(scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], hiddenimports=None, hookspath=None, runtime_hooks=[], **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex[:] pathex.append(specpath) exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if icon_file: exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = map(quote_win_filepath, resources) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] scripts = map(Path, scripts) d = {'scripts': scripts, 'pathex': pathex, 'hiddenimports': hiddenimports, 'name': name, 'debug': debug, 'strip': strip, 'upx': not noupx, 'exe_options': exe_options, # Directory with additional custom import hooks. 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks, # only Windows and Mac OS X distinguish windowed and console apps 'console': console, } if is_win or is_cygwin: d['exename'] = name + '.exe' d['dllname'] = name + '.dll' else: d['exename'] = name # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + '.spec') specfile = open(specfnm, 'w') if comserver: specfile.write(comsrvrtmplt % d) elif onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) specfile.close() return specfnm
def build(spec, distpath, workpath, clean_build): """ Build the executable according to the created SPEC file. """ from PyInstaller.config import CONF # Ensure starting tilde and environment variables get expanded in distpath / workpath. # '~/path/abc', '${env_var_name}/path/abc/def' distpath = compat.expand_path(distpath) workpath = compat.expand_path(workpath) CONF['spec'] = compat.expand_path(spec) CONF['specpath'], CONF['specnm'] = os.path.split(spec) CONF['specnm'] = os.path.splitext(CONF['specnm'])[0] # Add 'specname' to workpath and distpath if they point to PyInstaller homepath. if os.path.dirname(distpath) == HOMEPATH: distpath = os.path.join(HOMEPATH, CONF['specnm'], os.path.basename(distpath)) CONF['distpath'] = distpath if os.path.dirname(workpath) == HOMEPATH: workpath = os.path.join(HOMEPATH, CONF['specnm'], os.path.basename(workpath), CONF['specnm']) else: workpath = os.path.join(workpath, CONF['specnm']) CONF['warnfile'] = os.path.join(workpath, 'warn-%s.txt' % CONF['specnm']) CONF['dot-file'] = os.path.join(workpath, 'graph-%s.dot' % CONF['specnm']) CONF['xref-file'] = os.path.join(workpath, 'xref-%s.html' % CONF['specnm']) # Clean PyInstaller cache (CONF['cachedir']) and temporary files (workpath) # to be able start a clean build. if clean_build: logger.info('Removing temporary files and cleaning cache in %s', CONF['cachedir']) for pth in (CONF['cachedir'], workpath): if os.path.exists(pth): # Remove all files in 'pth'. for f in glob.glob(pth + '/*'): # Remove dirs recursively. if os.path.isdir(f): shutil.rmtree(f) else: os.remove(f) # Create DISTPATH and workpath if they does not exist. for pth in (CONF['distpath'], workpath): if not os.path.exists(pth): os.makedirs(pth) # Construct NAMESPACE for running the Python code from .SPEC file. # NOTE: Passing NAMESPACE allows to avoid having global variables in this # module and makes isolated environment for running tests. # NOTE: Defining NAMESPACE allows to map any class to a apecific name for .SPEC. # FIXME: Some symbols might be missing. Add them if there are some failures. # TODO: What from this .spec API is deprecated and could be removed? spec_namespace = { # Set of global variables that can be used while processing .spec file. # Some of them act as configuration options. 'DISTPATH': CONF['distpath'], 'HOMEPATH': HOMEPATH, 'SPEC': CONF['spec'], 'specnm': CONF['specnm'], 'SPECPATH': CONF['specpath'], 'WARNFILE': CONF['warnfile'], 'workpath': workpath, # PyInstaller classes for .spec. 'TOC': TOC, 'Analysis': Analysis, 'BUNDLE': BUNDLE, 'COLLECT': COLLECT, 'EXE': EXE, 'MERGE': MERGE, 'PYZ': PYZ, 'Tree': Tree, 'Splash': Splash, # Python modules available for .spec. 'os': os, 'pyi_crypto': pyz_crypto, } # Set up module PyInstaller.config for passing some arguments to 'exec' # function. from PyInstaller.config import CONF CONF['workpath'] = workpath # Execute the specfile. Read it as a binary file... try: with open(spec, 'rb') as f: # ... then let Python determine the encoding, since ``compile`` accepts # byte strings. code = compile(f.read(), spec, 'exec') except FileNotFoundError as e: raise SystemExit('spec "{}" not found'.format(spec)) exec(code, spec_namespace)
def main( scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], hiddenimports=None, hookspath=None, runtime_hooks=[], **kwargs ): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex[:] pathex.append(specpath) exe_options = "" if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) # Icon file for OSX. # We need to encapsulate it into apostrofes. icon_file = "'%s'" % icon_file else: # On OSX default icon has to be copied into the .app bundle. # The the text value 'None' means - use default icon. icon_file = "None" if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = map(quote_win_filepath, resources) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] scripts = map(Path, scripts) d = { "scripts": scripts, "pathex": pathex, "hiddenimports": hiddenimports, "name": name, "debug": debug, "strip": strip, "upx": not noupx, "exe_options": exe_options, # Directory with additional custom import hooks. "hookspath": hookspath, # List with custom runtime hook files. "runtime_hooks": runtime_hooks, # only Windows and Mac OS X distinguish windowed and console apps "console": console, # Icon filename. Only OSX uses this item. "icon": icon_file, } if is_win or is_cygwin: d["exename"] = name + ".exe" d["dllname"] = name + ".dll" else: d["exename"] = name # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + ".spec") specfile = open(specfnm, "w") if comserver: specfile.write(comsrvrtmplt % d) elif onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) specfile.close() return specfnm
def main(scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], hiddenimports=None, hookspath=None, runtime_hooks=[], **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex[:] pathex.append(specpath) exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) # Icon file for OSX. # We need to encapsulate it into apostrofes. icon_file = "'%s'" % icon_file else: # On OSX default icon has to be copied into the .app bundle. # The the text value 'None' means - use default icon. icon_file = 'None' if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = map(quote_win_filepath, resources) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] scripts = map(Path, scripts) d = { 'scripts': scripts, 'pathex': pathex, 'hiddenimports': hiddenimports, 'name': name, 'debug': debug, 'strip': strip, 'upx': not noupx, 'exe_options': exe_options, # Directory with additional custom import hooks. 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks, # only Windows and Mac OS X distinguish windowed and console apps 'console': console, # Icon filename. Only OSX uses this item. 'icon': icon_file, } if is_win or is_cygwin: d['exename'] = name + '.exe' d['dllname'] = name + '.dll' else: d['exename'] = name # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + '.spec') specfile = open(specfnm, 'w') if comserver: specfile.write(comsrvrtmplt % d) elif onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) specfile.close() return specfnm
def main(scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], bundle_identifier=None, hiddenimports=None, hookspath=None, key=None, runtime_hooks=[], excludes=[], uac_admin=False, uac_uiaccess=False, **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex[:] pathex.append(specpath) # Handle additional EXE options. exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if uac_admin: exe_options = "%s, uac_admin=%s" % (exe_options, 'True') if uac_uiaccess: exe_options = "%s, uac_uiaccess=%s" % (exe_options, 'True') if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) # Icon file for OSX. # We need to encapsulate it into apostrofes. icon_file = "'%s'" % icon_file else: # On OSX default icon has to be copied into the .app bundle. # The the text value 'None' means - use default icon. icon_file = 'None' if bundle_identifier: # We need to encapsulate it into apostrofes. bundle_identifier = "'%s'" % bundle_identifier if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = map(quote_win_filepath, resources) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] scripts = map(Path, scripts) if key: # Tries to import PyCrypto since we need it for bytecode obfuscation. Also make sure its # version is >= 2.4. try: import Crypto pycrypto_version = map(int, Crypto.__version__.split('.')) is_version_acceptable = pycrypto_version[0] >= 2 and pycrypto_version[1] >= 4 if not is_version_acceptable: logger.error('PyCrypto version must be >= 2.4, older versions are not supported.') sys.exit(1) except ImportError: logger.error('We need PyCrypto >= 2.4 to use byte-code obufscation but we could not') logger.error('find it. You can install it with pip by running:') logger.error(' pip install PyCrypto') sys.exit(1) cipher_init = cipher_init_template % {'key': key} else: cipher_init = cipher_absent_template d = {'scripts': scripts, 'pathex': pathex, 'hiddenimports': hiddenimports, 'name': name, 'debug': debug, 'strip': strip, 'upx': not noupx, 'exe_options': exe_options, 'cipher_init': cipher_init, # Directory with additional custom import hooks. 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks, # List of modules/pakages to ignore. 'excludes': excludes, # only Windows and Mac OS X distinguish windowed and console apps 'console': console, # Icon filename. Only OSX uses this item. 'icon': icon_file, # .app bundle identifier. Only OSX uses this item. 'bundle_identifier': bundle_identifier, } if is_win or is_cygwin: d['exename'] = name + '.exe' d['dllname'] = name + '.dll' else: d['exename'] = name # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + '.spec') specfile = open(specfnm, 'w') if comserver: specfile.write(comsrvrtmplt % d) elif onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) specfile.close() return specfnm
def main(scripts, name=None, onefile=None, console=True, debug=None, strip=False, noupx=False, upx_exclude=None, runtime_tmpdir=None, pathex=None, version_file=None, specpath=None, bootloader_ignore_signals=False, disable_windowed_traceback=False, datas=None, binaries=None, icon_file=None, manifest=None, resources=None, bundle_identifier=None, hiddenimports=None, hookspath=None, key=None, runtime_hooks=None, excludes=None, uac_admin=False, uac_uiaccess=False, win_no_prefer_redirects=False, win_private_assemblies=False, collect_submodules=None, collect_binaries=None, collect_data=None, collect_all=None, copy_metadata=None, splash=None, recursive_copy_metadata=None, target_arch=None, codesign_identity=None, entitlements_file=None, **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex or [] pathex = pathex[:] pathex.append(specpath) # Handle additional EXE options. exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if uac_admin: exe_options = "%s, uac_admin=%s" % (exe_options, 'True') if uac_uiaccess: exe_options = "%s, uac_uiaccess=%s" % (exe_options, 'True') if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) # Icon file for OSX. # We need to encapsulate it into apostrofes. icon_file = "'%s'" % icon_file else: # On OSX default icon has to be copied into the .app bundle. # The the text value 'None' means - use default icon. icon_file = 'None' if bundle_identifier: # We need to encapsulate it into apostrofes. bundle_identifier = "'%s'" % bundle_identifier if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = list(map(quote_win_filepath, resources)) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] upx_exclude = upx_exclude or [] # If file extension of the first script is '.pyw', force --windowed option. if is_win and os.path.splitext(scripts[0])[-1] == '.pyw': console = False # If script paths are relative, make them relative to the directory containing .spec file. scripts = [make_path_spec_relative(x, specpath) for x in scripts] # With absolute paths replace prefix with variable HOMEPATH. scripts = list(map(Path, scripts)) if key: # Tries to import tinyaes since we need it for bytecode obfuscation. try: import tinyaes # noqa: F401 (test import) except ImportError: logger.error('We need tinyaes to use byte-code obfuscation but we ' 'could not') logger.error('find it. You can install it with pip by running:') logger.error(' pip install tinyaes') sys.exit(1) cipher_init = cipher_init_template % {'key': key} else: cipher_init = cipher_absent_template # Translate the default of ``debug=None`` to an empty list. if debug is None: debug = [] # Translate the ``all`` option. if DEBUG_ALL_CHOICE[0] in debug: debug = DEBUG_ARGUMENT_CHOICES # Create preamble (for collect_*() calls) preamble = Preamble(datas, binaries, hiddenimports, collect_data, collect_binaries, collect_submodules, collect_all, copy_metadata, recursive_copy_metadata) if splash: splash_init = splashtmpl % {'splash_image': splash} splash_binaries = ( "\n" + " " * (10 if onefile else 15) # noqa: W503 + "splash.binaries,") # noqa: W503 splash_target = "\n" + " " * 10 + "splash," else: splash_init = splash_binaries = splash_target = "" d = { 'scripts': scripts, 'pathex': pathex, 'binaries': preamble.binaries, 'datas': preamble.datas, 'hiddenimports': preamble.hiddenimports, 'preamble': preamble.content, 'name': name, 'noarchive': 'noarchive' in debug, 'options': [('v', None, 'OPTION')] if 'imports' in debug else [], 'debug_bootloader': 'bootloader' in debug, 'bootloader_ignore_signals': bootloader_ignore_signals, 'strip': strip, 'upx': not noupx, 'upx_exclude': upx_exclude, 'runtime_tmpdir': runtime_tmpdir, 'exe_options': exe_options, 'cipher_init': cipher_init, # Directory with additional custom import hooks. 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks or [], # List of modules/pakages to ignore. 'excludes': excludes or [], # only Windows and Mac OS X distinguish windowed and console apps 'console': console, 'disable_windowed_traceback': disable_windowed_traceback, # Icon filename. Only OSX uses this item. 'icon': icon_file, # .app bundle identifier. Only OSX uses this item. 'bundle_identifier': bundle_identifier, # Target architecture (macOS only) 'target_arch': target_arch, # Code signing identity (macOS only) 'codesign_identity': codesign_identity, # Entitlements file (macOS only) 'entitlements_file': entitlements_file, # Windows assembly searching options 'win_no_prefer_redirects': win_no_prefer_redirects, 'win_private_assemblies': win_private_assemblies, # splash screen 'splash_init': splash_init, 'splash_target': splash_target, 'splash_binaries': splash_binaries, } # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + '.spec') with open(specfnm, 'w', encoding='utf-8') as specfile: if onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) return specfnm
def main(scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], bundle_identifier=None, hiddenimports=None, hookspath=None, key=None, runtime_hooks=[], excludes=[], uac_admin=False, uac_uiaccess=False, **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] # If specpath not specified - use default value - current working directory. if specpath is None: specpath = DEFAULT_SPECPATH else: # Expand tilde to user's home directory. specpath = expand_path(specpath) # If cwd is the root directory of PyInstaller then generate .spec file # subdirectory ./appname/. if specpath == HOMEPATH: specpath = os.path.join(HOMEPATH, name) # Create directory tree if missing. if not os.path.exists(specpath): os.makedirs(specpath) # Append specpath to PYTHONPATH - where to look for additional Python modules. pathex = pathex[:] pathex.append(specpath) # Handle additional EXE options. exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) if uac_admin: exe_options = "%s, uac_admin=%s" % (exe_options, 'True') if uac_uiaccess: exe_options = "%s, uac_uiaccess=%s" % (exe_options, 'True') if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) # Icon file for OSX. # We need to encapsulate it into apostrofes. icon_file = "'%s'" % icon_file else: # On OSX default icon has to be copied into the .app bundle. # The the text value 'None' means - use default icon. icon_file = 'None' if bundle_identifier: # We need to encapsulate it into apostrofes. bundle_identifier = "'%s'" % bundle_identifier if manifest: if "<" in manifest: # Assume XML string exe_options = "%s, manifest='%s'" % (exe_options, manifest.replace("'", "\\'")) else: # Assume filename exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest)) if resources: resources = map(quote_win_filepath, resources) exe_options = "%s, resources=%s" % (exe_options, repr(resources)) hiddenimports = hiddenimports or [] scripts = map(Path, scripts) if key: # Tries to import PyCrypto since we need it for bytecode obfuscation. Also make sure its # version is >= 2.4. try: import Crypto pycrypto_version = map(int, Crypto.__version__.split('.')) is_version_acceptable = pycrypto_version[ 0] >= 2 and pycrypto_version[1] >= 4 if not is_version_acceptable: logger.error( 'PyCrypto version must be >= 2.4, older versions are not supported.' ) sys.exit(1) except ImportError: logger.error( 'We need PyCrypto >= 2.4 to use byte-code obufscation but we could not' ) logger.error('find it. You can install it with pip by running:') logger.error(' pip install PyCrypto') sys.exit(1) cipher_init = cipher_init_template % {'key': key} else: cipher_init = cipher_absent_template d = { 'scripts': scripts, 'pathex': pathex, 'hiddenimports': hiddenimports, 'name': name, 'debug': debug, 'strip': strip, 'upx': not noupx, 'exe_options': exe_options, 'cipher_init': cipher_init, # Directory with additional custom import hooks. 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks, # List of modules/pakages to ignore. 'excludes': excludes, # only Windows and Mac OS X distinguish windowed and console apps 'console': console, # Icon filename. Only OSX uses this item. 'icon': icon_file, # .app bundle identifier. Only OSX uses this item. 'bundle_identifier': bundle_identifier, } if is_win or is_cygwin: d['exename'] = name + '.exe' d['dllname'] = name + '.dll' else: d['exename'] = name # Write down .spec file to filesystem. specfnm = os.path.join(specpath, name + '.spec') specfile = open(specfnm, 'w') if comserver: specfile.write(comsrvrtmplt % d) elif onefile: specfile.write(onefiletmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundleexetmplt % d) else: specfile.write(onedirtmplt % d) # For OSX create .app bundle. if is_darwin and not console: specfile.write(bundletmplt % d) specfile.close() return specfnm