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)
def test_add_to_suffix__extension(): toc = [ ('mypkg', 'lib38/site-packages/mypkg' + EXTENSION_SUFFIXES[0], 'EXTENSION'), ] toc = utils.add_suffix_to_extensions(toc) assert toc == [ ('mypkg' + EXTENSION_SUFFIXES[0], 'lib38/site-packages/mypkg' + EXTENSION_SUFFIXES[0], 'EXTENSION'), ]
def assemble(self): _make_clean_directory(self.name) logger.info("Building COLLECT %s", self.tocbasename) 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).split(os.sep) \ 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) elif not os.path.isdir(todir): raise SystemExit( "Pyinstaller needs to make a directory, but there " "already is a file at that path. " "The file at issue is {!r}".format(todir)) if typ in ('EXTENSION', 'BINARY'): fnm = checkCache(fnm, strip=self.strip_binaries, upx=self.upx_binaries, upx_exclude=self.upx_exclude, dist_nm=inm) if typ != 'DEPENDENCY': 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) try: shutil.copystat(fnm, tofnm) except OSError: logger.warning("failed to copy flags of %s", fnm) if typ in ('EXTENSION', 'BINARY'): os.chmod(tofnm, 0o755) logger.info("Building COLLECT %s completed successfully.", self.tocbasename)
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))
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)
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, # Fix for #156 - 'MacOS' must be in the name - not sure why "CFBundleExecutable": 'MacOS/%s' % 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 = [] toc = add_suffix_to_extensions(self.toc) for inm, fnm, typ in toc: # 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) # Add most data files to a list for symlinking later. if typ == 'DATA' and base_path not in ('PySide2', 'PyQt5'): 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))
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))