Example #1
0
    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)
Example #2
0
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
Example #3
0
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)
Example #4
0
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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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