def packDistFolderToOnefileWindows(dist_dir): general.warning("Onefile mode is experimental on '%s'." % getOS()) postprocessing_logger.info( "Creating single file from dist folder, this may take a while.") onefile_output_filename = getResultFullpath(onefile=True) # First need to create the bootstrap binary for unpacking. _runOnefileScons(quiet=not Options.isShowScons()) # Make sure to copy the resources from the created binary to the bootstrap binary, these # are icons and version information. copyResourcesFromFileToFile( source_filename=getResultFullpath(onefile=False), target_filename=onefile_output_filename, resource_kinds=(RT_ICON, RT_GROUP_ICON, RT_VERSION), ) # Now need to append to payload it, potentially compressing it. compression_indicator, compressor = _pickCompressor() with open(onefile_output_filename, "ab") as output_file: # Seeking to end of file seems necessary on Python2 at least, maybe it's # just that tell reports wrong value initially. output_file.seek(0, 2) start_pos = output_file.tell() output_file.write(b"KA" + compression_indicator) # Move the binary to start immediately to the start position start_binary = getResultFullpath(onefile=False) file_list = getFileList(dist_dir) file_list.remove(start_binary) file_list.insert(0, start_binary) for filename_full in file_list: filename_relative = os.path.relpath(filename_full, dist_dir) filename_encoded = filename_relative.encode("utf-16le") + b"\0\0" output_file.write(filename_encoded) with open(filename_full, "rb") as input_file: compressed = compressor(input_file.read()) output_file.write(struct.pack("Q", len(compressed))) output_file.write(compressed) # Using empty filename as a terminator. output_file.write(b"\0\0") output_file.write(struct.pack("Q", start_pos))
def packDistFolderToOnefileBootstrap(onefile_output_filename, dist_dir): postprocessing_logger.info( "Creating single file from dist folder, this may take a while.") onefile_logger.info("Running bootstrap binary compilation via Scons.") # Now need to append to payload it, potentially compressing it. compressor_python = getCompressorPython() # First need to create the bootstrap binary for unpacking. _runOnefileScons( quiet=not Options.isShowScons(), onefile_compression=compressor_python is not None, ) if isWin32Windows(): executePostProcessingResources(manifest=None, onefile=True) Plugins.onBootstrapBinary(onefile_output_filename) if isMacOS(): addMacOSCodeSignature(filenames=[onefile_output_filename]) runOnefileCompressor( compressor_python=compressor_python, dist_dir=dist_dir, onefile_output_filename=onefile_output_filename, start_binary=getResultFullpath(onefile=False), )
def packDistFolderToOnefileWindows(dist_dir): postprocessing_logger.info( "Creating single file from dist folder, this may take a while." ) onefile_output_filename = getResultFullpath(onefile=True) general.info("Running bootstrap binary compilation via Scons.") # First need to create the bootstrap binary for unpacking. _runOnefileScons(quiet=not Options.isShowScons()) # Now need to append to payload it, potentially compressing it. compression_indicator, compressor = _pickCompressor() with open(onefile_output_filename, "ab") as output_file: # Seeking to end of file seems necessary on Python2 at least, maybe it's # just that tell reports wrong value initially. output_file.seek(0, 2) start_pos = output_file.tell() output_file.write(b"KA" + compression_indicator) # Move the binary to start immediately to the start position start_binary = getResultFullpath(onefile=False) file_list = getFileList(dist_dir) file_list.remove(start_binary) file_list.insert(0, start_binary) for filename_full in file_list: filename_relative = os.path.relpath(filename_full, dist_dir) filename_encoded = filename_relative.encode("utf-16le") + b"\0\0" output_file.write(filename_encoded) with open(filename_full, "rb") as input_file: compressed = compressor(input_file.read()) output_file.write(struct.pack("Q", len(compressed))) output_file.write(compressed) # Using empty filename as a terminator. output_file.write(b"\0\0") output_file.write(struct.pack("Q", start_pos))
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.isExperimental("onefile-bootstrap"): packDistFolderToOnefileBootstrap(onefile_output_filename, dist_dir) elif getOS() == "Linux": 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)
def packDistFolderToOnefileLinux(dist_dir, binary_filename): """Pack to onefile binary on Linux. Notes: This is mostly a wrapper around AppImage, which does all the heavy lifting. """ # This might be possible to avoid being done with --runtime-file. apprun_filename = os.path.join(dist_dir, "AppRun") with open(apprun_filename, "w") as output_file: output_file.write( """\ #!/bin/sh exec $APPDIR/%s $@""" % os.path.basename(binary_filename) ) addFileExecutablePermission(apprun_filename) binary_basename = os.path.basename(getResultBasepath()) icon_paths = getIconPaths() assert icon_paths extension = os.path.splitext(icon_paths[0])[1].lower() shutil.copyfile(icon_paths[0], getResultBasepath() + extension) with open(getResultBasepath() + ".desktop", "w") as output_file: output_file.write( """\ [Desktop Entry] Name=%(binary_basename)s Exec=%(binary_filename)s Icon=%(binary_basename)s Type=Application Categories=Utility;""" % { "binary_basename": binary_basename, "binary_filename": os.path.basename(binary_filename), } ) postprocessing_logger.info( "Creating single file from dist folder, this may take a while." ) onefile_output_filename = getResultFullpath(onefile=True) # Starting the process while locked, so file handles are not duplicated. appimagetool_process = subprocess.Popen( ( getAppImageToolPath(), dist_dir, "--comp", "xz", "-n", onefile_output_filename, ), shell=False, stderr=getNullOutput(), stdout=getNullOutput(), ) # TODO: Exit code should be checked. result = appimagetool_process.wait() if not os.path.exists(onefile_output_filename): postprocessing_logger.sysexit( "Error, expected output file %s not created by AppImage." % onefile_output_filename ) postprocessing_logger.info("Completed onefile creation.") assert result == 0, result