extends RefCounted class_name KiriPythonBuildWrangler var _python_release_info : Dictionary = {} func _get_python_release_info(): if _python_release_info == {}: var this_script_path = get_script().resource_path var this_script_dir = this_script_path.get_base_dir() var release_info_path = this_script_dir.path_join("StandalonePythonBuilds/python_release_info.json") _python_release_info = load(release_info_path).data return _python_release_info func _get_python_version(): var info = _get_python_release_info() var versions : Array = info["versions"] # Sort version numbers so that the highest version is the first element. versions.sort_custom(func(a : String, b : String): var version_parts_a : PackedStringArray = a.split(".") var version_parts_b : PackedStringArray = b.split(".") for i in range(0, 3): if int(version_parts_a[i]) > int(version_parts_b[i]): return true if int(version_parts_a[i]) < int(version_parts_b[i]): return false return false) return versions[0] func _get_python_release(): var info = _get_python_release_info() return info["release"] func _generate_python_archive_string( python_version : String, python_release : String, arch : String, os : String, opt : String): return "cpython-{python_version}+{python_release}-{python_arch}-{python_os}-{python_opt}-full.tar.zip".format( { "python_version" : python_version, "python_release" : python_release, "python_arch" : arch, "python_os" : os, "python_opt" : opt }) func _get_python_opt_for_os(os_name : String) -> String: if os_name == "pc-windows-msvc-shared": return "pgo" return "pgo+lto" func _detect_archive_for_runtime( \ python_version : String, python_release : String): var arch : String = _get_python_architecture(Engine.get_architecture_name()) var os_name : String = _get_python_platform(OS.get_name(), arch) var opt = _get_python_opt_for_os(os_name) var archive_str : String = _generate_python_archive_string( python_version, python_release, arch, os_name, opt) return archive_str func _detect_archive_for_build( python_version : String, python_release : String, arch : String, os_name : String): var opt = _get_python_opt_for_os(os_name) var archive_str : String = _generate_python_archive_string( python_version, python_release, arch, os_name, opt) return archive_str # Note: arch variable is output of _get_python_architecture, not whatever Godot # returns. func _get_python_platform(os_name : String, arch : String) -> String: var os_name_mappings : Dictionary = { "Linux" : "unknown-linux-gnu", "macOS" : "apple-darwin", "Windows" : "pc-windows-msvc-shared" } # Special case for armv7 Linux: if arch == "armv7" and os_name == "Linux": return "linux-gnueabi" assert(os_name_mappings.has(os_name)) return os_name_mappings[os_name] func _get_python_architecture(engine_arch : String) -> String: var arch_name_mappings : Dictionary = { "x86_64" : "x86_64", "x86_32" : "i686", "arm64" : "aarch64", # FIXME: I dunno if this is correct. "arm32" : "armv7", # FIXME: I dunno if this is correct. } assert(arch_name_mappings.has(engine_arch)) return arch_name_mappings[engine_arch] func _get_cache_path_relative(): return "_python_dist".path_join(_get_python_release()).path_join(_get_python_version()) func _get_cache_path_system(): return OS.get_user_data_dir().path_join(_get_cache_path_relative()) func _get_cache_path_godot(): return "user://".path_join(_get_cache_path_relative()) func _get_runtime_python_archive_godot_path() -> String: var this_script_path = get_script().resource_path var this_script_dir = this_script_path.get_base_dir() var python_archive_path = this_script_dir.path_join( "StandalonePythonBuilds").path_join( _detect_archive_for_runtime( _get_python_version(), _get_python_release())) return python_archive_path func get_export_python_archive_godot_path(platform : String, arch : String) -> String: var this_script_path = get_script().resource_path var this_script_dir = this_script_path.get_base_dir() var python_archive_path = this_script_dir.path_join( "StandalonePythonBuilds").path_join( _detect_archive_for_build( _get_python_version(), _get_python_release(), arch, platform)) return python_archive_path func _unpack_python(): var python_archive_path = _get_runtime_python_archive_godot_path() var reader : TARReader = TARReader.new() reader.open(python_archive_path) #print(reader.get_files()) var file_list : PackedStringArray = reader.get_files() for relative_filename : String in file_list: reader.unpack_file(_get_cache_path_godot(), relative_filename) pass func _get_runtime_python_executable_godot_path(): var base_dir = _get_cache_path_godot().path_join("python/install") if OS.get_name() == "Windows": return base_dir.path_join("python.exe") else: return base_dir.path_join("bin/python3") # TODO: Other platforms. # Testing code follows... #func _ready(): # #print(_detect_archive_for_runtime( #_get_python_version(), _get_python_release())) # #print(_get_cache_path_godot()) #print(_get_cache_path_system()) #print(_get_runtime_python_archive_godot_path()) # ##_unpack_python() #print(_get_runtime_python_executable_godot_path()) #print(ProjectSettings.globalize_path(_get_runtime_python_executable_godot_path())) # #var out = [] #OS.execute( #ProjectSettings.globalize_path(_get_runtime_python_executable_godot_path()), #["asdfjknsdcjknsdcjknsdjkc"], out, true) #print(out) # #