Exemplo n.º 1
0
def _expandProjectArg(arg, filename_arg, for_eval):
    def wrap(value):
        if for_eval:
            return repr(value)
        else:
            return value

    values = {
        "OS": wrap(getOS()),
        "Arch": wrap(getArchitecture()),
        "Flavor": wrap(_getPythonFlavor()),
        "Version": getNuitkaVersion(),
        "Commercial": wrap(getCommercialVersion()),
        "MAIN_DIRECTORY": wrap(os.path.dirname(filename_arg) or "."),
    }

    if isLinux():
        dist_info = getLinuxDistribution()
    else:
        dist_info = "N/A", "N/A", "0"

    values["Linux_Distribution_Name"] = dist_info[0]
    values["Linux_Distribution_Base"] = dist_info[1] or dist_info[0]
    values["Linux_Distribution_Version"] = dist_info[2]

    if getOS() == "Windows":
        values["WindowsRelease"] = getWindowsRelease()

    arg = arg.format(**values)

    return arg
Exemplo n.º 2
0
def _getVersionInformationValues():
    # TODO: Might be nice if we could delay version information computation
    # until it's actually used.
    yield getNuitkaVersion()
    yield "Commercial: %s" % getCommercialVersion()
    yield "Python: %s" % sys.version.split("\n", 1)[0]
    yield "Flavor: %s" % _getPythonFlavor()
    yield "Executable: %s" % sys.executable
    yield "OS: %s" % getOS()
    yield "Arch: %s" % getArchitecture()

    if isLinux():
        dist_name, dist_base, dist_version = getLinuxDistribution()

        if dist_base is not None:
            yield "Distribution: %s (based on %s) %s" % (
                dist_name,
                dist_base,
                dist_version,
            )
        else:
            yield "Distribution: %s %s" % (dist_name, dist_version)

    if getOS() == "Windows":
        yield "WindowsRelease: %s" % getWindowsRelease()
Exemplo n.º 3
0
    def onBootstrapBinary(self, filename):
        if not isLinux():
            return

        if self.upx_binary is not None:
            self._compressFile(filename=filename, use_cache=False)
        else:
            self._warnNoUpx()
Exemplo n.º 4
0
def isOnefileTempDirMode():
    """:returns: bool derived from ``--onefile-tempdir`` and OS

    Notes:
        On all but Linux, using a bootstrap binary that does unpack is mandatory,
        but on Linux, the AppImage tool is used by default, this enforces using
        a bootstrap binary there too.
    """
    return not isLinux() or options.is_onefile_tempdir
Exemplo n.º 5
0
def checkOnefileReadiness(assume_yes_for_downloads):
    if isLinux():
        app_image_path = _getAppImageToolPath(
            for_operation=False,
            assume_yes_for_downloads=assume_yes_for_downloads)

        return app_image_path is not None
    else:
        return hasOnefileSupportedOS()
Exemplo n.º 6
0
    def onFinalResult(self, filename):
        if isLinux() and isOnefileMode():
            if not isOnefileTempDirMode():
                self.warning(
                    "UPX cannot compress '%s' as AppImage doesn't support that."
                    % filename)

            # Bootstrap was compressed already right after creation.
            return
        else:
            if self.upx_binary is not None:
                self._compressFile(filename=filename, use_cache=False)
            else:
                self._warnNoUpx()
Exemplo n.º 7
0
def packDistFolderToOnefile(dist_dir, binary_filename):
    """Pack distribution to onefile, i.e. a single file that is directly executable."""

    onefile_output_filename = getResultFullpath(onefile=True)

    if getOS() == "Windows" or Options.isOnefileTempDirMode():
        packDistFolderToOnefileBootstrap(onefile_output_filename, dist_dir)
    elif isLinux():
        packDistFolderToOnefileLinux(onefile_output_filename, dist_dir,
                                     binary_filename)
    else:
        postprocessing_logger.sysexit(
            "Onefile mode is not yet available on %r." % getOS())

    Plugins.onOnefileFinished(onefile_output_filename)
Exemplo n.º 8
0
def isDebianPackagePython():
    """Is this Python from a debian package."""

    if not isLinux():
        return False

    if python_version < 0x300:
        return hasattr(sys, "_multiarch")
    else:
        with withNoDeprecationWarning():
            try:
                from distutils.dir_util import _multiarch
            except ImportError:
                return False
            else:
                return True
Exemplo n.º 9
0
def getIconPaths():
    """*list of str*, values of ``--windows-icon-from-ico`` and ``--linux-onefile-icon``"""

    result = options.icon_path

    # Check if Linux icon requirement is met.
    if isLinux() and not result and isOnefileMode():
        default_icons = (
            "/usr/share/pixmaps/python%s.xpm" % python_version_str,
            "/usr/share/pixmaps/python%s.xpm" % sys.version_info[0],
            "/usr/share/pixmaps/python.xpm",
        )

        for icon in default_icons:
            if os.path.exists(icon):
                result.append(icon)
                break
        else:
            Tracing.options_logger.sysexit("""\
Error, none of the default icons '%s' exist, making '--linux-onefile-icon' required."""
                                           % ", ".join(default_icons))

    return result
Exemplo n.º 10
0
    def getImplicitImports(self, module):
        # Dealing with OpenGL is a bit detailed, pylint: disable=too-many-branches
        if module.getFullName() == "OpenGL":
            opengl_infos = self.queryRuntimeInformationSingle(
                setup_codes="import OpenGL.plugins",
                value=
                "[(f.name, f.import_path) for f in OpenGL.plugins.FormatHandler.all()]",
            )

            # TODO: Filter by name.
            for _name, import_path in opengl_infos:
                yield ModuleName(import_path).getPackageName()

            for line in getFileContentByLine(module.getCompileTimeFilename()):
                if line.startswith("PlatformPlugin("):
                    os_part, plugin_name_part = line[15:-1].split(",")
                    os_part = os_part.strip("' ")
                    plugin_name_part = plugin_name_part.strip(") '")
                    plugin_name_part = plugin_name_part[:plugin_name_part.
                                                        rfind(".")]

                    if os_part == "nt":
                        if getOS() == "Windows":
                            yield plugin_name_part
                    elif os_part.startswith("linux"):
                        if isLinux():
                            yield plugin_name_part
                    elif os_part.startswith("darwin"):
                        if isMacOS():
                            yield plugin_name_part
                    elif os_part.startswith(("posix", "osmesa", "egl")):
                        if getOS() != "Windows":
                            yield plugin_name_part
                    else:
                        self.sysexit(
                            "Undetected OS, please report bug for '%s'." %
                            os_part)
Exemplo n.º 11
0
def parseArgs():
    """Parse the command line arguments

    :meta private:
    """
    # singleton with many cases checking the options right away.
    # pylint: disable=global-statement,too-many-branches,too-many-locals,too-many-statements
    global is_nuitka_run, options, positional_args, extra_args, is_debug, is_nondebug
    global is_fullcompat, is_report_missing, is_verbose

    if os.name == "nt":
        # Windows store Python's don't allow looking at the python, catch that.
        try:
            with openTextFile(sys.executable, "rb"):
                pass
        except OSError:
            Tracing.general.sysexit(
                "Error, the Python from Windows store is not supported, check the User Manual of Nuitka ."
            )

    is_nuitka_run, options, positional_args, extra_args = parseOptions(
        logger=Tracing.options_logger)

    is_debug = _isDebug()
    is_nondebug = not is_debug
    is_fullcompat = _isFullCompat()

    # TODO: Have dedicated option for it.
    is_report_missing = is_debug

    if options.quiet or int(os.environ.get("NUITKA_QUIET", "0")):
        Tracing.setQuiet()

    if not shallDumpBuiltTreeXML():
        Tracing.options_logger.info("Used command line options: %s" %
                                    " ".join(sys.argv[1:]))

    if os.environ.get("NUITKA_REEXECUTION") and not isAllowedToReexecute():
        Tracing.general.sysexit(
            "Error, not allowed to re-execute, but that has happened.")

    if options.progress_bar:
        Progress.enableProgressBar()

    if options.verbose_output:
        Tracing.optimization_logger.setFileHandle(
            # Can only have unbuffered binary IO in Python3, therefore not disabling buffering here.
            openTextFile(options.verbose_output, "w", encoding="utf8"))

        options.verbose = True

    is_verbose = options.verbose

    Tracing.optimization_logger.is_quiet = not options.verbose

    if options.show_inclusion_output:
        Tracing.inclusion_logger.setFileHandle(
            # Can only have unbuffered binary IO in Python3, therefore not disabling buffering here.
            openTextFile(options.show_inclusion_output, "w", encoding="utf8"))

        options.show_inclusion = True

    Tracing.progress_logger.is_quiet = not options.show_progress

    # Onefile implies standalone build.
    if options.is_onefile:
        options.is_standalone = True

    # Standalone implies no_site build
    if options.is_standalone:
        options.python_flags.insert(0, "no_site")

    # Provide a tempdir spec implies onefile tempdir, even on Linux.
    if options.onefile_tempdir_spec:
        options.is_onefile_tempdir = True

        if os.path.normpath(options.onefile_tempdir_spec) == ".":
            Tracing.options_logger.sysexit("""\
Error, using '.' as a value for '--onefile-tempdir-spec' is not supported,
you cannot unpack the onefile payload into the same directory as the binary,
as that would overwrite it and cause locking issues as well.""")

        if options.onefile_tempdir_spec.count("%") % 2 != 0:
            Tracing.options_logger.warning(
                """Unmatched '%%' is suspicious for '--onefile-tempdir-spec' and may
not do what you want it to do: '%s'""" % options.onefile_tempdir_spec)

        if options.onefile_tempdir_spec.count("%") == 0:
            Tracing.options_logger.warning(
                """Not using any variables for '--onefile-tempdir-spec' should only be
done if your program absolutely needs to be in the same path always: '%s'""" %
                options.onefile_tempdir_spec)

        if os.path.isabs(options.onefile_tempdir_spec):
            Tracing.options_logger.warning(
                """Using an absolute path should be avoided unless you are targeting a
very well known environment: '%s'""" % options.onefile_tempdir_spec)
        elif relpath(options.onefile_tempdir_spec):
            Tracing.options_logger.warning(
                """Using an relative path above the executable should be avoided unless you are targeting a
very well known environment: '%s'""" % options.onefile_tempdir_spec)

    # Standalone mode implies an executable, not importing "site" module, which is
    # only for this machine, recursing to all modules, and even including the
    # standard library.
    if options.is_standalone:
        if options.module_mode:
            Tracing.options_logger.sysexit("""\
Error, conflicting options, cannot make standalone module, only executable.

Modules are supposed to be imported to an existing Python installation, therefore it
makes no sense to include a Python runtime.""")

    for any_case_module in getShallFollowModules():
        if any_case_module.startswith("."):
            bad = True
        else:
            for char in "/\\:":
                if char in any_case_module:
                    bad = True
                    break
            else:
                bad = False

        if bad:
            Tracing.options_logger.sysexit("""\
Error, '--follow-import-to' takes only module names or patterns, not directory path '%s'."""
                                           % any_case_module)

    for no_case_module in getShallFollowInNoCase():
        if no_case_module.startswith("."):
            bad = True
        else:
            for char in "/\\:":
                if char in no_case_module:
                    bad = True
                    break
            else:
                bad = False

        if bad:
            Tracing.options_logger.sysexit("""\
Error, '--nofollow-import-to' takes only module names or patterns, not directory path '%s'."""
                                           % no_case_module)

    scons_python = getPythonPathForScons()

    if scons_python is not None and not os.path.isfile(scons_python):
        Tracing.options_logger.sysexit(
            "Error, no such Python binary %r, should be full path." %
            scons_python)

    if options.output_filename is not None and (
        (isStandaloneMode() and not isOnefileMode()) or shallMakeModule()):
        Tracing.options_logger.sysexit("""\
Error, may only specify output filename for acceleration and onefile mode,
but not for module mode where filenames are mandatory, and not for
standalone where there is a sane default used inside the dist folder.""")

    if isLinux():
        if len(getIconPaths()) > 1:
            Tracing.options_logger.sysexit(
                "Error, can only use one icon file on Linux.")

    if isMacOS():
        if len(getIconPaths()) > 1:
            Tracing.options_logger.sysexit(
                "Error, can only use one icon file on macOS.")

    for icon_path in getIconPaths():
        if "#" in icon_path and isWin32Windows():
            icon_path, icon_index = icon_path.rsplit("#", 1)

            if not icon_index.isdigit() or int(icon_index) < 0:
                Tracing.options_logger.sysexit(
                    "Error, icon number in %r not valid." %
                    (icon_path + "#" + icon_index))

        if not os.path.exists(icon_path):
            Tracing.options_logger.sysexit(
                "Error, icon path %r does not exist." % icon_path)

        if getWindowsIconExecutablePath():
            Tracing.options_logger.sysexit(
                "Error, can only use icons from template executable or from icon files, but not both."
            )

    icon_exe_path = getWindowsIconExecutablePath()
    if icon_exe_path is not None and not os.path.exists(icon_exe_path):
        Tracing.options_logger.sysexit("Error, icon path %r does not exist." %
                                       icon_exe_path)

    try:
        file_version = getWindowsFileVersion()
    except Exception:  # Catch all the things, don't want any interface, pylint: disable=broad-except
        Tracing.options_logger.sysexit(
            "Error, file version must be a tuple of up to 4 integer values.")

    try:
        product_version = getWindowsProductVersion()
    except Exception:  # Catch all the things, don't want any interface, pylint: disable=broad-except
        Tracing.options_logger.sysexit(
            "Error, product version must be a tuple of up to 4 integer values."
        )

    if getWindowsCompanyName() == "":
        Tracing.options_logger.sysexit(
            """Error, empty string is not an acceptable company name.""")

    if getWindowsProductName() == "":
        Tracing.options_logger.sysexit(
            """Error, empty string is not an acceptable product name.""")

    splash_screen_filename = getWindowsSplashScreen()

    if splash_screen_filename is not None:
        if not os.path.isfile(splash_screen_filename):
            Tracing.options_logger.sysexit(
                "Error, specified splash screen image '%s' does not exist." %
                splash_screen_filename)

    if file_version or product_version or getWindowsVersionInfoStrings():
        if not (file_version or product_version) and getWindowsCompanyName():
            Tracing.options_logger.sysexit(
                "Error, company name and file or product version need to be given when any version information is given."
            )

    if isOnefileMode() and not hasOnefileSupportedOS():
        Tracing.options_logger.sysexit("Error, unsupported OS for onefile %r" %
                                       getOS())

    if options.follow_none and options.follow_all:
        Tracing.options_logger.sysexit(
            "Conflicting options '--follow-imports' and '--nofollow-imports' given."
        )

    for module_pattern in getShallIncludePackageData():
        if (module_pattern.startswith("-") or "/" in module_pattern
                or "\\" in module_pattern):
            Tracing.options_logger.sysexit(
                "Error, '--include-package-data' needs module name or pattern as an argument, not %r."
                % module_pattern)

    for module_pattern in getShallFollowModules():
        if (module_pattern.startswith("-") or "/" in module_pattern
                or "\\" in module_pattern):
            Tracing.options_logger.sysexit(
                "Error, '--follow-import-to' options needs module name or pattern as an argument, not %r."
                % module_pattern)
    for module_pattern in getShallFollowInNoCase():
        if (module_pattern.startswith("-") or "/" in module_pattern
                or "\\" in module_pattern):
            Tracing.options_logger.sysexit(
                "Error, '--nofollow-import-to' options needs module name or pattern as an argument, not %r."
                % module_pattern)

    for data_file in options.data_files:
        if "=" not in data_file:
            Tracing.options_logger.sysexit(
                "Error, malformed data file description, must specify relative target path separated with '='."
            )

        if data_file.count("=") == 1:
            src, dst = data_file.split("=", 1)

            filenames = resolveShellPatternToFilenames(src)

            if len(filenames) > 1 and not dst.endswith(("/", os.path.sep)):
                Tracing.options_logger.sysexit(
                    "Error, pattern '%s' matches more than one file, but target has no trailing slash, not a directory."
                    % src)
        else:
            src, dst, pattern = data_file.split("=", 2)

            filenames = resolveShellPatternToFilenames(
                os.path.join(src, pattern))

        if not filenames:
            Tracing.options_logger.sysexit(
                "Error, '%s' does not match any files." % src)

        if os.path.isabs(dst):
            Tracing.options_logger.sysexit(
                "Error, must specify relative target path for data file, not absolute path '%s'."
                % data_file)

    for data_dir in options.data_dirs:
        if "=" not in data_dir:
            Tracing.options_logger.sysexit(
                "Error, malformed data dir description, must specify relative target path with '=' separating it."
            )

        src, dst = data_dir.split("=", 1)

        if os.path.isabs(dst):
            Tracing.options_logger.sysexit(
                "Error, must specify relative target path for data dir, not %r as in %r."
                % (dst, data_dir))

        if not os.path.isdir(src):
            Tracing.options_logger.sysexit(
                "Error, must specify existing source data directory, not %r as in %r."
                % (dst, data_dir))

    for pattern in getShallFollowExtraFilePatterns():
        if os.path.isdir(pattern):
            Tracing.options_logger.sysexit(
                "Error, pattern %r given to '--include-plugin-files' cannot be a directory name."
                % pattern)

    if options.static_libpython == "yes" and getSystemStaticLibPythonPath(
    ) is None:
        Tracing.options_logger.sysexit(
            "Error, static libpython is not found or not supported for this Python installation."
        )

    if shallUseStaticLibPython() and getSystemStaticLibPythonPath() is None:
        Tracing.options_logger.sysexit(
            """Error, usable static libpython is not found for this Python installation. You \
might be missing required packages. Disable with --static-libpython=no" if you don't \
want to install it.""")

    if isApplePython():
        if isStandaloneMode():
            Tracing.options_logger.sysexit(
                "Error, for standalone mode, Apple Python from macOS is not supported, use e.g. CPython instead."
            )

        if str is bytes:
            Tracing.options_logger.sysexit(
                "Error, Apple Python 2.7 from macOS is not usable as per Apple decision, use e.g. CPython 2.7 instead."
            )

    if isStandaloneMode() and isLinux(
    ) and getExecutablePath("patchelf") is None:
        Tracing.options_logger.sysexit(
            "Error, standalone mode on Linux requires 'patchelf' to be installed. Use 'apt/dnf/yum install patchelf' first."
        )

    pgo_executable = getPgoExecutable()
    if pgo_executable and not isPathExecutable(pgo_executable):
        Tracing.options_logger.sysexit(
            "Error, path '%s' to binary to use for PGO is not executable." %
            pgo_executable)