Beispiel #1
0
    def assemble(self):
        logger.info("Building PYZ (ZlibArchive) %s", self.name)
        # Do not bundle PyInstaller bootstrap modules into PYZ archive.
        toc = self.toc - self.dependencies
        for entry in toc[:]:
            if not entry[0] in self.code_dict and entry[2] == 'PYMODULE':
                # For some reason the code-object, modulegraph created
                # is not available. Recreate it
                try:
                    self.code_dict[entry[0]] = get_code_object(entry[0], entry[1])
                except SyntaxError:
                    # Exclude the module in case this is code meant for a newer Python version.
                    toc.remove(entry)
        # sort content alphabetically to support reproducible builds
        toc.sort()

        # Remove leading parts of paths in code objects
        self.code_dict = {
            key: strip_paths_in_code(code)
            for key, code in self.code_dict.items()
        }

        pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
        logger.info("Building PYZ (ZlibArchive) %s completed successfully.",
                    self.name)
Beispiel #2
0
 def assemble(self):
     if _check_path_overlap(self.name) and os.path.isdir(self.name):
         _rmtree(self.name)
     logger.info("Building COLLECT %s", self.tocbasename)
     os.makedirs(self.name)
     toc = add_suffix_to_extensions(self.toc)
     for inm, fnm, typ in toc:
         if not os.path.exists(fnm) or not os.path.isfile(fnm) and is_path_to_egg(fnm):
             # file is contained within python egg, it is added with the egg
             continue
         if os.pardir in os.path.normpath(inm) or os.path.isabs(inm):
             raise SystemExit('Security-Alert: try to store file outside '
                              'of dist-directory. Aborting. %r' % inm)
         tofnm = os.path.join(self.name, inm)
         todir = os.path.dirname(tofnm)
         if not os.path.exists(todir):
             os.makedirs(todir)
         if typ in ('EXTENSION', 'BINARY'):
             fnm = checkCache(fnm, strip=self.strip_binaries,
                              upx=(self.upx_binaries and (is_win or is_cygwin)),
                              dist_nm=inm)
         if typ != 'DEPENDENCY':
             shutil.copy(fnm, tofnm)
             try:
                 shutil.copystat(fnm, tofnm)
             except OSError:
                 logger.warn("failed to copy flags of %s", fnm)
         if typ in ('EXTENSION', 'BINARY'):
             os.chmod(tofnm, 0o755)
Beispiel #3
0
    def assemble(self):
        logger.info("Building PYZ (ZlibArchive) %s", self.name)
        # Do not bundle PyInstaller bootstrap modules into PYZ archive.
        toc = self.toc - self.dependencies
        for entry in toc[:]:
            if not entry[0] in self.code_dict and entry[2] == 'PYMODULE':
                # For some reason the code-object, modulegraph created
                # is not available. Recreate it
                try:
                    self.code_dict[entry[0]] = get_code_object(entry[0], entry[1])
                except SyntaxError:
                    # Exclude the module in case this is code meant for a newer Python version.
                    toc.remove(entry)
        # sort content alphabetically to support reproducible builds
        toc.sort()

        # Remove leading parts of paths in code objects
        self.code_dict = {
            key: strip_paths_in_code(code)
            for key, code in self.code_dict.items()
        }

        pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
        logger.info("Building PYZ (ZlibArchive) %s completed successfully.",
                    self.name)
Beispiel #4
0
    def __init__(self, *args):
        """
        Repeated dependencies are then present only once in the first
        executable in the 'args' list. Other executables depend on the
        first one. Other executables have to extract necessary files
        from the first executable.

        args  dependencies in a list of (Analysis, id, filename) tuples.
              Replace id with the correct filename.
        """
        # The first Analysis object with all dependencies.
        # Any item from the first executable cannot be removed.
        self._main = None

        self._dependencies = {}

        self._id_to_path = {}
        for _, i, p in args:
            self._id_to_path[os.path.normcase(i)] = p

        # Get the longest common path
        self._common_prefix = os.path.dirname(os.path.commonprefix([os.path.abspath(a.scripts[-1][1]) for a, _, _ in args]))
        if self._common_prefix[-1] != os.sep:
            self._common_prefix += os.sep
        logger.info("Common prefix: %s", self._common_prefix)

        self._merge_dependencies(args)
Beispiel #5
0
 def assemble(self):
     logger.info("Building PYZ (ZlibArchive) %s", self.name)
     # Do not bundle PyInstaller bootstrap modules into PYZ archive.
     toc = self.toc - self.dependencies
     for entry in toc:
         if not entry[0] in self.code_dict and entry[2] == 'PYMODULE':
             # For some reason the code-object, modulegraph created
             # is not available. Recreate it
             self.code_dict[entry[0]] = self.__get_code(entry[0], entry[1])
     pyz = ZlibArchiveWriter(code_dict=self.code_dict, cipher=self.cipher)
     pyz.build(self.name, toc)
Beispiel #6
0
    def _check_guts(self, data, last_build):
        if not os.path.exists(self.name):
            logger.info("Rebuilding %s because %s missing",
                        self.tocbasename, os.path.basename(self.name))
            return 1
        if not self.append_pkg and not os.path.exists(self.pkgname):
            logger.info("Rebuilding because %s missing",
                        os.path.basename(self.pkgname))
            return 1

        if Target._check_guts(self, data, last_build):
            return True

        if (data['versrsrc'] or data['resources']) and not is_win:
            # todo: really ignore :-)
            logger.warn('ignoring version, manifest and resources, platform not capable')
        if data['icon'] and not (is_win or is_darwin):
            logger.warn('ignoring icon, platform not capable')

        mtm = data['mtm']
        if mtm != misc.mtime(self.name):
            logger.info("Rebuilding %s because mtimes don't match", self.tocbasename)
            return True
        if mtm < misc.mtime(self.pkg.tocfilename):
            logger.info("Rebuilding %s because pkg is more recent", self.tocbasename)
            return True
        return False
Beispiel #7
0
    def assemble(self):
        logger.info("Building PYZ (ZlibArchive) %s", self.name)
        # Do not bundle PyInstaller bootstrap modules into PYZ archive.
        toc = self.toc - self.dependencies
        for entry in toc:
            if not entry[0] in self.code_dict and entry[2] == 'PYMODULE':
                # For some reason the code-object, modulegraph created
                # is not available. Recreate it
                self.code_dict[entry[0]] = self.__get_code(entry[0], entry[1])
        # sort content alphabetically to support reproducible builds
        toc.sort()

        # Remove leading parts of paths in code objects
        self.code_dict = {
            key: self._strip_paths_in_code(code)
            for key, code in self.code_dict.items()
        }

        pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
Beispiel #8
0
    def assemble(self):
        logger.info("Building PYZ (ZlibArchive) %s", self.name)
        # Do not bundle PyInstaller bootstrap modules into PYZ archive.
        toc = self.toc - self.dependencies
        for entry in toc:
            if not entry[0] in self.code_dict and entry[2] == 'PYMODULE':
                # For some reason the code-object, modulegraph created
                # is not available. Recreate it
                self.code_dict[entry[0]] = get_code_object(entry[0], entry[1])
        # sort content alphabetically to support reproducible builds
        toc.sort()

        # Remove leading parts of paths in code objects
        self.code_dict = {
            key: strip_paths_in_code(code)
            for key, code in self.code_dict.items()
        }

        pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
Beispiel #9
0
 def _bootloader_file(self, exe, extension=None):
     """
     Pick up the right bootloader file - debug, console, windowed.
     """
     # Having console/windowed bootolader makes sense only on Windows and
     # Mac OS X.
     if is_win or is_darwin:
         if not self.console:
             exe = exe + 'w'
     # There are two types of bootloaders:
     # run     - release, no verbose messages in console.
     # run_d   - contains verbose messages in console.
     if self.debug:
         exe = exe + '_d'
     if extension:
         exe = exe + extension
     bootloader_file = os.path.join(HOMEPATH, 'PyInstaller', 'bootloader', PLATFORM, exe)
     logger.info('Bootloader %s' % bootloader_file)
     return bootloader_file
Beispiel #10
0
    def assemble(self):
        if _check_path_overlap(self.name) and os.path.isdir(self.name):
            _rmtree(self.name)
        logger.info("Building BUNDLE %s", self.tocbasename)

        # Create a minimal Mac bundle structure
        os.makedirs(os.path.join(self.name, "Contents", "MacOS"))
        os.makedirs(os.path.join(self.name, "Contents", "Resources"))
        os.makedirs(os.path.join(self.name, "Contents", "Frameworks"))

        # Copy icns icon to Resources directory.
        if os.path.exists(self.icon):
            shutil.copy(self.icon,
                        os.path.join(self.name, 'Contents', 'Resources'))
        else:
            logger.warning("icon not found %s", self.icon)

        # Key/values for a minimal Info.plist file
        info_plist_dict = {
            "CFBundleDisplayName": self.appname,
            "CFBundleName": self.appname,

            # Required by 'codesign' utility.
            # The value for CFBundleIdentifier is used as the default unique
            # name of your program for Code Signing purposes.
            # It even identifies the APP for access to restricted OS X areas
            # like Keychain.
            #
            # The identifier used for signing must be globally unique. The usal
            # form for this identifier is a hierarchical name in reverse DNS
            # notation, starting with the toplevel domain, followed by the
            # company name, followed by the department within the company, and
            # ending with the product name. Usually in the form:
            #   com.mycompany.department.appname
            # Cli option --osx-bundle-identifier sets this value.
            "CFBundleIdentifier": self.bundle_identifier,
            "CFBundleExecutable": os.path.basename(self.exename),
            "CFBundleIconFile": os.path.basename(self.icon),
            "CFBundleInfoDictionaryVersion": "6.0",
            "CFBundlePackageType": "APPL",
            "CFBundleShortVersionString": self.version,
        }

        # Set some default values.
        # But they still can be overwritten by the user.
        if self.console:
            # Setting EXE console=True implies LSBackgroundOnly=True.
            info_plist_dict['LSBackgroundOnly'] = True
        else:
            # Let's use high resolution by default.
            info_plist_dict['NSHighResolutionCapable'] = True

        # Merge info_plist settings from spec file
        if isinstance(self.info_plist, dict) and self.info_plist:
            info_plist_dict.update(self.info_plist)

        plist_filename = os.path.join(self.name, "Contents", "Info.plist")
        with open(plist_filename, "wb") as plist_fh:
            plistlib.dump(info_plist_dict, plist_fh)

        links = []
        _QT_BASE_PATH = {'PySide2', 'PySide6', 'PyQt5', 'PySide6'}
        for inm, fnm, typ in self.toc:
            # Adjust name for extensions, if applicable
            inm, fnm, typ = add_suffix_to_extension(inm, fnm, typ)
            # Copy files from cache. This ensures that are used files with relative
            # paths to dynamic library dependencies (@executable_path)
            base_path = inm.split('/', 1)[0]
            if typ in ('EXTENSION', 'BINARY'):
                fnm = checkCache(fnm,
                                 strip=self.strip,
                                 upx=self.upx,
                                 upx_exclude=self.upx_exclude,
                                 dist_nm=inm,
                                 target_arch=self.target_arch,
                                 codesign_identity=self.codesign_identity,
                                 entitlements_file=self.entitlements_file)
            # Add most data files to a list for symlinking later.
            if typ == 'DATA' and base_path not in _QT_BASE_PATH:
                links.append((inm, fnm))
            else:
                tofnm = os.path.join(self.name, "Contents", "MacOS", inm)
                todir = os.path.dirname(tofnm)
                if not os.path.exists(todir):
                    os.makedirs(todir)
                if os.path.isdir(fnm):
                    # beacuse shutil.copy2() is the default copy function
                    # for shutil.copytree, this will also copy file metadata
                    shutil.copytree(fnm, tofnm)
                else:
                    shutil.copy(fnm, tofnm)

        logger.info('Moving BUNDLE data files to Resource directory')

        # Mac OS X Code Signing does not work when .app bundle contains
        # data files in dir ./Contents/MacOS.
        #
        # Put all data files in ./Resources and create symlinks in ./MacOS.
        bin_dir = os.path.join(self.name, 'Contents', 'MacOS')
        res_dir = os.path.join(self.name, 'Contents', 'Resources')
        for inm, fnm in links:
            tofnm = os.path.join(res_dir, inm)
            todir = os.path.dirname(tofnm)
            if not os.path.exists(todir):
                os.makedirs(todir)
            if os.path.isdir(fnm):
                # beacuse shutil.copy2() is the default copy function
                # for shutil.copytree, this will also copy file metadata
                shutil.copytree(fnm, tofnm)
            else:
                shutil.copy(fnm, tofnm)
            base_path = os.path.split(inm)[0]
            if base_path:
                if not os.path.exists(os.path.join(bin_dir, inm)):
                    path = ''
                    for part in iter(base_path.split(os.path.sep)):
                        # Build path from previous path and the next part of the base path
                        path = os.path.join(path, part)
                        try:
                            relative_source_path = os.path.relpath(
                                os.path.join(res_dir, path),
                                os.path.split(os.path.join(bin_dir, path))[0])
                            dest_path = os.path.join(bin_dir, path)
                            os.symlink(relative_source_path, dest_path)
                            break
                        except FileExistsError:
                            pass
                    if not os.path.exists(os.path.join(bin_dir, inm)):
                        relative_source_path = os.path.relpath(
                            os.path.join(res_dir, inm),
                            os.path.split(os.path.join(bin_dir, inm))[0])
                        dest_path = os.path.join(bin_dir, inm)
                        os.symlink(relative_source_path, dest_path)
            else:  # If path is empty, e.g., a top level file, try to just symlink the file
                os.symlink(
                    os.path.relpath(
                        os.path.join(res_dir, inm),
                        os.path.split(os.path.join(bin_dir, inm))[0]),
                    os.path.join(bin_dir, inm))

        # Sign the bundle
        logger.info('Signing the BUNDLE...')
        try:
            osxutils.sign_binary(self.name,
                                 self.codesign_identity,
                                 self.entitlements_file,
                                 deep=True)
        except Exception as e:
            logger.warning("Error while signing the bundle: %s", e)
            logger.warning("You will need to sign the bundle manually!")

        logger.info("Building BUNDLE %s completed successfully.",
                    self.tocbasename)
Beispiel #11
0
    def assemble(self):
        logger.info("Building PKG (CArchive) %s", os.path.basename(self.name))
        trash = []
        mytoc = []
        srctoc = []
        seenInms = {}
        seenFnms = {}
        seenFnms_typ = {}
        toc = add_suffix_to_extensions(self.toc)
        # 'inm'  - relative filename inside a CArchive
        # 'fnm'  - absolute filename as it is on the file system.
        for inm, fnm, typ in toc:
            # Ensure filename 'fnm' is not None or empty string. Otherwise
            # it will fail in case of 'typ' being type OPTION.
            if fnm and not os.path.isfile(fnm) and is_path_to_egg(fnm):
                # file is contained within python egg, it is added with the egg
                continue
            if typ in ('BINARY', 'EXTENSION', 'DEPENDENCY'):
                if self.exclude_binaries and typ != 'DEPENDENCY':
                    self.dependencies.append((inm, fnm, typ))
                else:
                    if typ == 'BINARY':
                        # Avoid importing the same binary extension twice. This might
                        # happen if they come from different sources (eg. once from
                        # binary dependence, and once from direct import).
                        if inm in seenInms:
                            logger.warning('Two binaries added with the same internal name.')
                            logger.warning(pprint.pformat((inm, fnm, typ)))
                            logger.warning('was placed previously at')
                            logger.warning(pprint.pformat((inm, seenInms[inm], seenFnms_typ[seenInms[inm]])))
                            logger.warning('Skipping %s.' % fnm)
                            continue

                        # Warn if the same binary extension was included
                        # with multiple internal names
                        if fnm in seenFnms:
                            logger.warning('One binary added with two internal names.')
                            logger.warning(pprint.pformat((inm, fnm, typ)))
                            logger.warning('was placed previously at')
                            logger.warning(pprint.pformat((seenFnms[fnm], fnm, seenFnms_typ[fnm])))
                    seenInms[inm] = fnm
                    seenFnms[fnm] = inm
                    seenFnms_typ[fnm] = typ

                    fnm = checkCache(fnm, strip=self.strip_binaries,
                                     upx=(self.upx_binaries and (is_win or is_cygwin)),
                                     dist_nm=inm)

                    mytoc.append((inm, fnm, self.cdict.get(typ, 0),
                                  self.xformdict.get(typ, 'b')))
            elif typ == 'OPTION':
                mytoc.append((inm, '', 0, 'o'))
            elif typ in ('PYSOURCE', 'PYMODULE'):
                # collect sourcefiles and module in a toc of it's own
                # which will not be sorted.
                srctoc.append((inm, fnm, self.cdict[typ], self.xformdict[typ]))
            else:
                mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b')))

        # Bootloader has to know the name of Python library. Pass python libname to CArchive.
        pylib_name = os.path.basename(bindepend.get_python_library_path())

        # Sort content alphabetically by type and name to support
        # reproducible builds.
        mytoc.sort(key=itemgetter(3, 0))
        # Do *not* sort modules and scripts, as their order is important.
        # TODO: Think about having all modules first and then all scripts.
        archive = CArchiveWriter(self.name, srctoc + mytoc,
                                 pylib_name=pylib_name)

        for item in trash:
            os.remove(item)
        logger.info("Building PKG (CArchive) %s completed successfully.",
                    os.path.basename(self.name))
Beispiel #12
0
    def assemble(self):
        logger.info("Building EXE from %s", self.tocbasename)
        trash = []
        if not os.path.exists(os.path.dirname(self.name)):
            os.makedirs(os.path.dirname(self.name))
        outf = open(self.name, 'wb')
        exe = self.exefiles[0][1]  # pathname of bootloader
        if not os.path.exists(exe):
            raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG)


        if is_win and (self.icon or self.versrsrc or self.resources):
            tmpnm = tempfile.mktemp()
            shutil.copy2(exe, tmpnm)
            os.chmod(tmpnm, 0o755)
            if self.icon:
                icon.CopyIcons(tmpnm, self.icon)
            if self.versrsrc:
                versioninfo.SetVersion(tmpnm, self.versrsrc)
            for res in self.resources:
                res = res.split(",")
                for i in range(1, len(res)):
                    try:
                        res[i] = int(res[i])
                    except ValueError:
                        pass
                resfile = res[0]
                restype = resname = reslang = None
                if len(res) > 1:
                    restype = res[1]
                if len(res) > 2:
                    resname = res[2]
                if len(res) > 3:
                    reslang = res[3]
                try:
                    winresource.UpdateResourcesFromResFile(tmpnm, resfile,
                                                        [restype or "*"],
                                                        [resname or "*"],
                                                        [reslang or "*"])
                except winresource.pywintypes.error as exc:
                    if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT:
                        logger.exception(exc)
                        continue
                    if not restype or not resname:
                        logger.error("resource type and/or name not specified")
                        continue
                    if "*" in (restype, resname):
                        logger.error("no wildcards allowed for resource type "
                                     "and name when source file does not "
                                     "contain resources")
                        continue
                    try:
                        winresource.UpdateResourcesFromDataFile(tmpnm,
                                                             resfile,
                                                             restype,
                                                             [resname],
                                                             [reslang or 0])
                    except winresource.pywintypes.error as exc:
                        logger.exception(exc)
            trash.append(tmpnm)
            exe = tmpnm
        exe = checkCache(exe, strip=self.strip, upx=self.upx)
        self.copy(exe, outf)
        if self.append_pkg:
            logger.info("Appending archive to EXE %s", self.name)
            self.copy(self.pkg.name, outf)
        else:
            logger.info("Copying archive to %s", self.pkgname)
            shutil.copy2(self.pkg.name, self.pkgname)
        outf.close()

        if is_darwin:
            # Fix Mach-O header for codesigning on OS X.
            logger.info("Fixing EXE for code signing %s", self.name)
            import PyInstaller.utils.osx as osxutils
            osxutils.fix_exe_for_code_signing(self.name)
            pass

        os.chmod(self.name, 0o755)
        # get mtime for storing into the guts
        self.mtm = misc.mtime(self.name)
        for item in trash:
            os.remove(item)
Beispiel #13
0
    def assemble(self):
        logger.info("Building EXE from %s", self.tocbasename)
        trash = []
        if os.path.exists(self.name):
            os.remove(self.name)
        if not os.path.exists(os.path.dirname(self.name)):
            os.makedirs(os.path.dirname(self.name))
        exe = self.exefiles[0][1]  # pathname of bootloader
        if not os.path.exists(exe):
            raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG)


        if is_win and (self.icon or self.versrsrc or self.resources):
            tmpnm = tempfile.mktemp()
            self._copyfile(exe, tmpnm)
            os.chmod(tmpnm, 0o755)
            if self.icon:
                icon.CopyIcons(tmpnm, self.icon)
            if self.versrsrc:
                versioninfo.SetVersion(tmpnm, self.versrsrc)
            for res in self.resources:
                res = res.split(",")
                for i in range(1, len(res)):
                    try:
                        res[i] = int(res[i])
                    except ValueError:
                        pass
                resfile = res[0]
                restype = resname = reslang = None
                if len(res) > 1:
                    restype = res[1]
                if len(res) > 2:
                    resname = res[2]
                if len(res) > 3:
                    reslang = res[3]
                try:
                    winresource.UpdateResourcesFromResFile(tmpnm, resfile,
                                                        [restype or "*"],
                                                        [resname or "*"],
                                                        [reslang or "*"])
                except winresource.pywintypes.error as exc:
                    if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT:
                        logger.error("Error while updating resources in %s"
                                     " from resource file %s", tmpnm, resfile, exc_info=1)
                        continue

                    # Handle the case where the file contains no resources, and is
                    # intended as a single resource to be added to the exe.
                    if not restype or not resname:
                        logger.error("resource type and/or name not specified")
                        continue
                    if "*" in (restype, resname):
                        logger.error("no wildcards allowed for resource type "
                                     "and name when source file does not "
                                     "contain resources")
                        continue
                    try:
                        winresource.UpdateResourcesFromDataFile(tmpnm,
                                                             resfile,
                                                             restype,
                                                             [resname],
                                                             [reslang or 0])
                    except winresource.pywintypes.error:
                        logger.error("Error while updating resource %s %s in %s"
                                     " from data file %s",
                                     restype, resname, tmpnm, resfile, exc_info=1)
            trash.append(tmpnm)
            exe = tmpnm

        # NOTE: Do not look up for bootloader file in the cache because it might
        #       get corrupted by UPX when UPX is available. See #1863 for details.

        if not self.append_pkg:
            logger.info("Copying bootloader exe to %s", self.name)
            self._copyfile(exe, self.name)
            logger.info("Copying archive to %s", self.pkgname)
            self._copyfile(self.pkg.name, self.pkgname)
        elif is_linux:
            self._copyfile(exe, self.name)
            logger.info("Appending archive to ELF section in EXE %s", self.name)
            retcode, stdout, stderr = exec_command_all(
                'objcopy', '--add-section', 'pydata=%s' % self.pkg.name,
                self.name)
            logger.debug("objcopy returned %i", retcode)
            if stdout:
                logger.debug(stdout)
            if stderr:
                logger.debug(stderr)
            if retcode != 0:
                raise SystemError("objcopy Failure: %s" % stderr)
        else:
            # Fall back to just append on end of file
            logger.info("Appending archive to EXE %s", self.name)
            with open(self.name, 'wb') as outf:
                # write the bootloader data
                with open(exe, 'rb') as infh:
                    shutil.copyfileobj(infh, outf, length=64*1024)
                # write the archive data
                with open(self.pkg.name, 'rb') as infh:
                    shutil.copyfileobj(infh, outf, length=64*1024)

        if is_darwin:
            # Fix Mach-O header for codesigning on OS X.
            logger.info("Fixing EXE for code signing %s", self.name)
            import PyInstaller.utils.osx as osxutils
            osxutils.fix_exe_for_code_signing(self.name)

        os.chmod(self.name, 0o755)
        # get mtime for storing into the guts
        self.mtm = misc.mtime(self.name)
        for item in trash:
            os.remove(item)
        logger.info("Building EXE from %s completed successfully.",
                    self.tocbasename)
Beispiel #14
0
    def assemble(self):
        logger.info("Building PKG (CArchive) %s", os.path.basename(self.name))
        trash = []
        mytoc = []
        seenInms = {}
        seenFnms = {}
        seenFnms_typ = {}
        toc = add_suffix_to_extensions(self.toc)
        # 'inm'  - relative filename inside a CArchive
        # 'fnm'  - absolute filename as it is on the file system.
        for inm, fnm, typ in toc:
            # Ensure filename 'fnm' is not None or empty string. Otherwise
            # it will fail in case of 'typ' being type OPTION.
            if fnm and not os.path.isfile(fnm) and is_path_to_egg(fnm):
                # file is contained within python egg, it is added with the egg
                continue
            if typ in ('BINARY', 'EXTENSION', 'DEPENDENCY'):
                if self.exclude_binaries and typ != 'DEPENDENCY':
                    self.dependencies.append((inm, fnm, typ))
                else:
                    if typ == 'BINARY':
                        # Avoid importing the same binary extension twice. This might
                        # happen if they come from different sources (eg. once from
                        # binary dependence, and once from direct import).
                        if inm in seenInms:
                            logger.warn('Two binaries added with the same internal name.')
                            logger.warn(pprint.pformat((inm, fnm, typ)))
                            logger.warn('was placed previously at')
                            logger.warn(pprint.pformat((inm, seenInms[inm], seenFnms_typ[seenInms[inm]])))
                            logger.warn('Skipping %s.' % fnm)
                            continue

                        # Warn if the same binary extension was included
                        # with multiple internal names
                        if fnm in seenFnms:
                            logger.warn('One binary added with two internal names.')
                            logger.warn(pprint.pformat((inm, fnm, typ)))
                            logger.warn('was placed previously at')
                            logger.warn(pprint.pformat((seenFnms[fnm], fnm, seenFnms_typ[fnm])))
                    seenInms[inm] = fnm
                    seenFnms[fnm] = inm
                    seenFnms_typ[fnm] = typ

                    fnm = checkCache(fnm, strip=self.strip_binaries,
                                     upx=(self.upx_binaries and (is_win or is_cygwin)),
                                     dist_nm=inm)

                    mytoc.append((inm, fnm, self.cdict.get(typ, 0),
                                  self.xformdict.get(typ, 'b')))
            elif typ == 'OPTION':
                mytoc.append((inm, '', 0, 'o'))
            else:
                mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b')))

        # Bootloader has to know the name of Python library. Pass python libname to CArchive.
        pylib_name = os.path.basename(bindepend.get_python_library_path())
        archive = CArchiveWriter(pylib_name=pylib_name)

        archive.build(self.name, mytoc)
        for item in trash:
            os.remove(item)
Beispiel #15
0
    def assemble(self):
        logger.info("Building PKG (CArchive) %s", os.path.basename(self.name))
        trash = []
        mytoc = []
        srctoc = []
        seenInms = {}
        seenFnms = {}
        seenFnms_typ = {}
        toc = add_suffix_to_extensions(self.toc)
        # 'inm'  - relative filename inside a CArchive
        # 'fnm'  - absolute filename as it is on the file system.
        for inm, fnm, typ in toc:
            # Ensure filename 'fnm' is not None or empty string. Otherwise
            # it will fail in case of 'typ' being type OPTION.
            if fnm and not os.path.isfile(fnm) and is_path_to_egg(fnm):
                # file is contained within python egg, it is added with the egg
                continue
            if typ in ('BINARY', 'EXTENSION', 'DEPENDENCY'):
                if self.exclude_binaries and typ != 'DEPENDENCY':
                    self.dependencies.append((inm, fnm, typ))
                else:
                    if typ == 'BINARY':
                        # Avoid importing the same binary extension twice. This might
                        # happen if they come from different sources (eg. once from
                        # binary dependence, and once from direct import).
                        if inm in seenInms:
                            logger.warning('Two binaries added with the same internal name.')
                            logger.warning(pprint.pformat((inm, fnm, typ)))
                            logger.warning('was placed previously at')
                            logger.warning(pprint.pformat((inm, seenInms[inm], seenFnms_typ[seenInms[inm]])))
                            logger.warning('Skipping %s.' % fnm)
                            continue

                        # Warn if the same binary extension was included
                        # with multiple internal names
                        if fnm in seenFnms:
                            logger.warning('One binary added with two internal names.')
                            logger.warning(pprint.pformat((inm, fnm, typ)))
                            logger.warning('was placed previously at')
                            logger.warning(pprint.pformat((seenFnms[fnm], fnm, seenFnms_typ[fnm])))
                    seenInms[inm] = fnm
                    seenFnms[fnm] = inm
                    seenFnms_typ[fnm] = typ

                    fnm = checkCache(fnm, strip=self.strip_binaries,
                                     upx=(self.upx_binaries and (is_win or is_cygwin)),
                                     dist_nm=inm)

                    mytoc.append((inm, fnm, self.cdict.get(typ, 0),
                                  self.xformdict.get(typ, 'b')))
            elif typ == 'OPTION':
                mytoc.append((inm, '', 0, 'o'))
            elif typ in ('PYSOURCE', 'PYMODULE'):
                # collect sourcefiles and module in a toc of it's own
                # which will not be sorted.
                srctoc.append((inm, fnm, self.cdict[typ], self.xformdict[typ]))
            else:
                mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b')))

        # Bootloader has to know the name of Python library. Pass python libname to CArchive.
        pylib_name = os.path.basename(bindepend.get_python_library_path())

        # Sort content alphabetically by type and name to support
        # reproducible builds.
        mytoc.sort(key=itemgetter(3, 0))
        # Do *not* sort modules and scripts, as their order is important.
        # TODO: Think about having all modules first and then all scripts.
        archive = CArchiveWriter(self.name, srctoc + mytoc,
                                 pylib_name=pylib_name)

        for item in trash:
            os.remove(item)
        logger.info("Building PKG (CArchive) %s completed successfully.",
                    os.path.basename(self.name))
Beispiel #16
0
    def __init__(self, *args, **kws):
        from PyInstaller.config import CONF

        # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms
        if not is_darwin:
            return

        # get a path to a .icns icon for the app bundle.
        self.icon = kws.get('icon')
        if not self.icon:
            # --icon not specified; use the default in the pyinstaller folder
            self.icon = os.path.join(
                os.path.dirname(os.path.dirname(__file__)), 'bootloader',
                'images', 'icon-windowed.icns')
        else:
            # user gave an --icon=path. If it is relative, make it
            # relative to the spec file location.
            if not os.path.isabs(self.icon):
                self.icon = os.path.join(CONF['specpath'], self.icon)
        # ensure icon path is absolute
        self.icon = os.path.abspath(self.icon)

        Target.__init__(self)

        # .app bundle is created in DISTPATH.
        self.name = kws.get('name', None)
        base_name = os.path.basename(self.name)
        self.name = os.path.join(CONF['distpath'], base_name)

        self.appname = os.path.splitext(base_name)[0]
        self.version = kws.get("version", "0.0.0")
        self.toc = TOC()
        self.strip = False
        self.upx = False
        self.console = True
        self.target_arch = None
        self.codesign_identity = None
        self.entitlements_file = None

        # .app bundle identifier for Code Signing
        self.bundle_identifier = kws.get('bundle_identifier')
        if not self.bundle_identifier:
            # Fallback to appname.
            self.bundle_identifier = self.appname

        self.info_plist = kws.get('info_plist', None)

        for arg in args:
            if isinstance(arg, EXE):
                self.toc.append(
                    (os.path.basename(arg.name), arg.name, arg.typ))
                self.toc.extend(arg.dependencies)
                self.strip = arg.strip
                self.upx = arg.upx
                self.upx_exclude = arg.upx_exclude
                self.console = arg.console
                self.target_arch = arg.target_arch
                self.codesign_identity = arg.codesign_identity
                self.entitlements_file = arg.entitlements_file
            elif isinstance(arg, TOC):
                self.toc.extend(arg)
                # TOC doesn't have a strip or upx attribute, so there is no way for us to
                # tell which cache we should draw from.
            elif isinstance(arg, COLLECT):
                self.toc.extend(arg.toc)
                self.strip = arg.strip_binaries
                self.upx = arg.upx_binaries
                self.upx_exclude = arg.upx_exclude
                self.console = arg.console
                self.target_arch = arg.target_arch
                self.codesign_identity = arg.codesign_identity
                self.entitlements_file = arg.entitlements_file
            else:
                logger.info("unsupported entry %s", arg.__class__.__name__)
        # Now, find values for app filepath (name), app name (appname), and name
        # of the actual executable (exename) from the first EXECUTABLE item in
        # toc, which might have come from a COLLECT too (not from an EXE).
        for inm, name, typ in self.toc:
            if typ == "EXECUTABLE":
                self.exename = name
                break
        self.__postinit__()
Beispiel #17
0
    def assemble(self):
        logger.info("Building EXE from %s", self.tocbasename)
        trash = []
        if not os.path.exists(os.path.dirname(self.name)):
            os.makedirs(os.path.dirname(self.name))
        exe = self.exefiles[0][1]  # pathname of bootloader
        if not os.path.exists(exe):
            raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG)


        if is_win and (self.icon or self.versrsrc or self.resources):
            tmpnm = tempfile.mktemp()
            self._copyfile(exe, tmpnm)
            os.chmod(tmpnm, 0o755)
            if self.icon:
                icon.CopyIcons(tmpnm, self.icon)
            if self.versrsrc:
                versioninfo.SetVersion(tmpnm, self.versrsrc)
            for res in self.resources:
                res = res.split(",")
                for i in range(1, len(res)):
                    try:
                        res[i] = int(res[i])
                    except ValueError:
                        pass
                resfile = res[0]
                restype = resname = reslang = None
                if len(res) > 1:
                    restype = res[1]
                if len(res) > 2:
                    resname = res[2]
                if len(res) > 3:
                    reslang = res[3]
                try:
                    winresource.UpdateResourcesFromResFile(tmpnm, resfile,
                                                        [restype or "*"],
                                                        [resname or "*"],
                                                        [reslang or "*"])
                except winresource.pywintypes.error as exc:
                    if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT:
                        logger.error("Error while updating resources in %s"
                                     " from resource file %s", tmpnm, resfile, exc_info=1)
                        continue

                    # Handle the case where the file contains no resources, and is
                    # intended as a single resource to be added to the exe.
                    if not restype or not resname:
                        logger.error("resource type and/or name not specified")
                        continue
                    if "*" in (restype, resname):
                        logger.error("no wildcards allowed for resource type "
                                     "and name when source file does not "
                                     "contain resources")
                        continue
                    try:
                        winresource.UpdateResourcesFromDataFile(tmpnm,
                                                             resfile,
                                                             restype,
                                                             [resname],
                                                             [reslang or 0])
                    except winresource.pywintypes.error:
                        logger.error("Error while updating resource %s %s in %s"
                                     " from data file %s",
                                     restype, resname, tmpnm, resfile, exc_info=1)
            trash.append(tmpnm)
            exe = tmpnm

        # NOTE: Do not look up for bootloader file in the cache because it might
        #       get corrupted by UPX when UPX is available. See #1863 for details.

        if not self.append_pkg:
            logger.info("Copying bootloader exe to %s", self.name)
            self._copyfile(exe, self.name)
            logger.info("Copying archive to %s", self.pkgname)
            self._copyfile(self.pkg.name, self.pkgname)
        elif is_linux:
            self._copyfile(exe, self.name)
            logger.info("Appending archive to ELF section in EXE %s", self.name)
            retcode, stdout, stderr = exec_command_all(
                'objcopy', '--add-section', 'pydata=%s' % self.pkg.name,
                self.name)
            logger.debug("objcopy returned %i", retcode)
            if stdout:
                logger.debug(stdout)
            if stderr:
                logger.debug(stderr)
            if retcode != 0:
                raise SystemError("objcopy Failure: %s" % stderr)
        else:
            # Fall back to just append on end of file
            logger.info("Appending archive to EXE %s", self.name)
            with open(self.name, 'wb') as outf:
                # write the bootloader data
                with open(exe, 'rb') as infh:
                    shutil.copyfileobj(infh, outf, length=64*1024)
                # write the archive data
                with open(self.pkg.name, 'rb') as infh:
                    shutil.copyfileobj(infh, outf, length=64*1024)

        if is_darwin:
            # Fix Mach-O header for codesigning on OS X.
            logger.info("Fixing EXE for code signing %s", self.name)
            import PyInstaller.utils.osx as osxutils
            osxutils.fix_exe_for_code_signing(self.name)

        os.chmod(self.name, 0o755)
        # get mtime for storing into the guts
        self.mtm = misc.mtime(self.name)
        for item in trash:
            os.remove(item)
        logger.info("Building EXE from %s completed successfully.",
                    self.tocbasename)