Moving stuff around.
This commit is contained in:
parent
5d3b74d798
commit
bdd56c30d1
@ -3,15 +3,11 @@ extends Node
|
|||||||
func _ready():
|
func _ready():
|
||||||
var bw : KiriPythonBuildWrangler = KiriPythonBuildWrangler.new()
|
var bw : KiriPythonBuildWrangler = KiriPythonBuildWrangler.new()
|
||||||
|
|
||||||
bw._unpack_python()
|
bw.unpack_python()
|
||||||
|
|
||||||
##_unpack_python()
|
|
||||||
#print(_get_runtime_python_executable_godot_path())
|
|
||||||
#print(ProjectSettings.globalize_path(_get_runtime_python_executable_godot_path()))
|
|
||||||
#
|
|
||||||
var out = []
|
var out = []
|
||||||
var ret = OS.execute(
|
var ret = OS.execute(
|
||||||
ProjectSettings.globalize_path(bw._get_runtime_python_executable_godot_path()),
|
bw.get_runtime_python_executable_system_path(),
|
||||||
["--version"], out, true)
|
["--version"], out, true)
|
||||||
|
|
||||||
print("Ret: ", ret)
|
print("Ret: ", ret)
|
||||||
|
@ -14,19 +14,17 @@ func _export_begin(
|
|||||||
var arch_list = []
|
var arch_list = []
|
||||||
|
|
||||||
if "linux" in features:
|
if "linux" in features:
|
||||||
#platform_list.append(build_wrangler._get_python_platform("Linux"))
|
|
||||||
platform_list.append("Linux")
|
platform_list.append("Linux")
|
||||||
if "windows" in features:
|
if "windows" in features:
|
||||||
platform_list.append("Windows")
|
platform_list.append("Windows")
|
||||||
if "x86_64" in features:
|
if "x86_64" in features:
|
||||||
arch_list.append("x86_64")
|
arch_list.append("x86_64")
|
||||||
|
|
||||||
|
# TODO: Other platforms (macos)
|
||||||
|
|
||||||
for platform in platform_list:
|
for platform in platform_list:
|
||||||
for arch in arch_list:
|
for arch in arch_list:
|
||||||
var python_arch : String = build_wrangler._get_python_architecture(arch)
|
var archive_to_export = build_wrangler._detect_archive_for_build(platform, arch)
|
||||||
var python_platform : String = build_wrangler._get_python_platform(platform, arch)
|
|
||||||
var archive_to_export = build_wrangler.get_export_python_archive_godot_path(python_platform, python_arch)
|
|
||||||
#print("EXPORT ME TOO: ", archive_to_export)
|
|
||||||
var file_contents : PackedByteArray = FileAccess.get_file_as_bytes(archive_to_export)
|
var file_contents : PackedByteArray = FileAccess.get_file_as_bytes(archive_to_export)
|
||||||
print("Adding file: ", archive_to_export, " ", len(file_contents))
|
print("Adding file: ", archive_to_export, " ", len(file_contents))
|
||||||
add_file(archive_to_export, file_contents, false)
|
add_file(archive_to_export, file_contents, false)
|
233
addons/KiriPythonRPCWrapper/KiriPythonBuildWrangler.gd
Normal file
233
addons/KiriPythonRPCWrapper/KiriPythonBuildWrangler.gd
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
extends RefCounted
|
||||||
|
class_name KiriPythonBuildWrangler
|
||||||
|
|
||||||
|
# Cached release info so we don't have to constantly reload the .json file.
|
||||||
|
var _python_release_info : Dictionary = {}
|
||||||
|
|
||||||
|
#region releaseinfo file interactions
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# If you hit this assert, your python_release_info.json file is probably
|
||||||
|
# missing and you missed a setup step. Check the README.
|
||||||
|
assert(_python_release_info != null)
|
||||||
|
|
||||||
|
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() -> String:
|
||||||
|
var info = _get_python_release_info()
|
||||||
|
return info["release"]
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Python archive filename wrangling
|
||||||
|
|
||||||
|
# Generate the archive filename based on what we've figured out from the release
|
||||||
|
# info, the platform, architecture, optimizations, and so on. This is just the
|
||||||
|
# filename, not including the full path.
|
||||||
|
#
|
||||||
|
# Use _generate_python_archive_full_path() to generate the full path (as a
|
||||||
|
# res:// path).
|
||||||
|
func _generate_python_archive_string(
|
||||||
|
python_version : String,
|
||||||
|
python_release : String,
|
||||||
|
arch : String,
|
||||||
|
os : String,
|
||||||
|
opt : String) -> 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
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get full path (in Godot) to the archive for a given Python build.
|
||||||
|
func _generate_python_archive_full_path(
|
||||||
|
python_version : String,
|
||||||
|
python_release : String,
|
||||||
|
arch : String,
|
||||||
|
os : String,
|
||||||
|
opt : String) -> String:
|
||||||
|
|
||||||
|
var just_the_archive_filename = _generate_python_archive_string(
|
||||||
|
python_version, python_release, arch, os, opt)
|
||||||
|
|
||||||
|
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(just_the_archive_filename)
|
||||||
|
|
||||||
|
return python_archive_path
|
||||||
|
|
||||||
|
# os_name as it appears in the Python archive filename.
|
||||||
|
func _get_python_opt_for_os(os_name : String) -> String:
|
||||||
|
if os_name == "pc-windows-msvc-shared":
|
||||||
|
return "pgo"
|
||||||
|
|
||||||
|
# TODO: (macos)
|
||||||
|
|
||||||
|
# Linux default.
|
||||||
|
return "pgo+lto"
|
||||||
|
|
||||||
|
# Note: arch variable is output of _get_python_architecture, not whatever Godot
|
||||||
|
# returns. os_name IS what Godot returns from OS.get_name().
|
||||||
|
func _get_python_platform(os_name : String, arch : String) -> String:
|
||||||
|
var os_name_mappings : Dictionary = {
|
||||||
|
"Linux" : "unknown-linux-gnu",
|
||||||
|
"macOS" : "apple-darwin", # TODO: Test this. (macos)
|
||||||
|
"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 _detect_archive_for_runtime() -> String:
|
||||||
|
var python_version : String = _get_python_version()
|
||||||
|
var python_release : String = _get_python_release()
|
||||||
|
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)
|
||||||
|
|
||||||
|
return _generate_python_archive_full_path(
|
||||||
|
python_version, python_release,
|
||||||
|
arch, os_name, opt)
|
||||||
|
|
||||||
|
# Params are Godot's names for OSes and architectures (eg "Windows", "Linux",
|
||||||
|
# etc), not Python archive filename fields. Use things like OS.get_name().
|
||||||
|
func _detect_archive_for_build(
|
||||||
|
os_name_from_godot : String,
|
||||||
|
arch_from_godot : String) -> String:
|
||||||
|
|
||||||
|
var python_version : String = _get_python_version()
|
||||||
|
var python_release : String = _get_python_release()
|
||||||
|
|
||||||
|
var arch : String = _get_python_architecture(arch_from_godot)
|
||||||
|
var os_name : String = _get_python_platform(os_name_from_godot, arch)
|
||||||
|
|
||||||
|
var opt = _get_python_opt_for_os(os_name)
|
||||||
|
|
||||||
|
return _generate_python_archive_full_path(
|
||||||
|
python_version, python_release,
|
||||||
|
arch, os_name, opt)
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Cache path wrangling
|
||||||
|
# Get the cache path, relative to the user data dir.
|
||||||
|
# Example return value:
|
||||||
|
# "_python_dist/20240415/3.12.3"
|
||||||
|
func _get_cache_path_relative():
|
||||||
|
return "_python_dist".path_join(_get_python_release()).path_join(_get_python_version())
|
||||||
|
|
||||||
|
# Get the full cache path, as understood by the OS.
|
||||||
|
# Example return value:
|
||||||
|
# "/home/kiri/.local/share/godot/app_userdata/GodotJSONRPCTest/_python_dist/20240415/3.12.3"
|
||||||
|
func _get_cache_path_system() -> String:
|
||||||
|
return OS.get_user_data_dir().path_join(_get_cache_path_relative())
|
||||||
|
|
||||||
|
# Get the full cache path, as understood by Godot.
|
||||||
|
# Example return value:
|
||||||
|
# "user://_python_dist/20240415/3.12.3"
|
||||||
|
func _get_cache_path_godot() -> String:
|
||||||
|
return "user://".path_join(_get_cache_path_relative())
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public API
|
||||||
|
|
||||||
|
# Get the expected path to the Python executable. This is where we think it'll
|
||||||
|
# end up, not where it actually did end up. This can be called without actually
|
||||||
|
# extracting the archive. In fact, we need it to act that way because we use it
|
||||||
|
# to determine if there's already a Python install in-place.
|
||||||
|
#
|
||||||
|
# Path is a Godot path. Use ProjectSettings.globalize_path() to conver to a
|
||||||
|
# system path.
|
||||||
|
#
|
||||||
|
# Example return:
|
||||||
|
# "user://_python_dist/20240415/3.12.3/python/install/bin/python3"
|
||||||
|
func get_runtime_python_executable_godot_path() -> String:
|
||||||
|
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 (macos).
|
||||||
|
|
||||||
|
# Get system path for the Python executable, which is what we actually need to
|
||||||
|
# use to execute it in most cases.
|
||||||
|
#
|
||||||
|
# Example return:
|
||||||
|
# "home/<user>/.local/share/godot/app_userdata/<project>/_python_dist/20240415/3.12.3/python/install/bin/python3"
|
||||||
|
func get_runtime_python_executable_system_path() -> String:
|
||||||
|
return ProjectSettings.globalize_path(get_runtime_python_executable_godot_path())
|
||||||
|
|
||||||
|
func unpack_python(overwrite : bool = false):
|
||||||
|
|
||||||
|
var cache_path_godot : String = _get_cache_path_godot()
|
||||||
|
|
||||||
|
# Check to see if the Python executable already exists. If it does, we might
|
||||||
|
# just skip unpacking.
|
||||||
|
var python_executable_expected_path : String = \
|
||||||
|
get_runtime_python_executable_godot_path()
|
||||||
|
if not overwrite:
|
||||||
|
if FileAccess.file_exists(python_executable_expected_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Open archive.
|
||||||
|
var python_archive_path : String = _detect_archive_for_runtime()
|
||||||
|
var reader : TARReader = TARReader.new()
|
||||||
|
var err : Error = reader.open(python_archive_path)
|
||||||
|
assert(err == OK)
|
||||||
|
|
||||||
|
# Get files.
|
||||||
|
var file_list : PackedStringArray = reader.get_files()
|
||||||
|
|
||||||
|
# Extract files.
|
||||||
|
for relative_filename : String in file_list:
|
||||||
|
reader.unpack_file(cache_path_godot, relative_filename)
|
||||||
|
|
||||||
|
# TODO: Clear cache function. Uninstall Python, etc.
|
||||||
|
|
||||||
|
#endregion
|
@ -10,7 +10,7 @@
|
|||||||
# DO NOT USE THIS ON UNTRUSTED DATA.
|
# DO NOT USE THIS ON UNTRUSTED DATA.
|
||||||
|
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
class_name TARReader
|
class_name KiriTARReader
|
||||||
|
|
||||||
#region Internal data
|
#region Internal data
|
||||||
|
|
||||||
@ -38,6 +38,10 @@ var _internal_file_list = []
|
|||||||
var _reader : ZIPReader = null
|
var _reader : ZIPReader = null
|
||||||
var _tar_file_cache : PackedByteArray = []
|
var _tar_file_cache : PackedByteArray = []
|
||||||
|
|
||||||
|
func _load_record(record : TarFileRecord) -> PackedByteArray:
|
||||||
|
load_cache()
|
||||||
|
return _tar_file_cache.slice(record.offset, record.offset + record.file_size)
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Cache wrangling
|
#region Cache wrangling
|
||||||
@ -69,6 +73,29 @@ func load_cache() -> Error:
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Number wrangling
|
||||||
|
|
||||||
|
func _octal_str_to_int(s : String) -> int:
|
||||||
|
var ret : int = 0;
|
||||||
|
var digit_multiplier = 1;
|
||||||
|
while len(s):
|
||||||
|
var lsb = s.substr(len(s) - 1, 1)
|
||||||
|
s = s.substr(0, len(s) - 1)
|
||||||
|
ret += digit_multiplier * lsb.to_int()
|
||||||
|
digit_multiplier *= 8
|
||||||
|
return ret
|
||||||
|
|
||||||
|
func _pad_to_512(x : int) -> int:
|
||||||
|
var x_lowbits = x & 511
|
||||||
|
var x_hibits = x & ~511
|
||||||
|
|
||||||
|
if x_lowbits:
|
||||||
|
x_hibits += 512
|
||||||
|
|
||||||
|
return x_hibits
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
func close() -> Error:
|
func close() -> Error:
|
||||||
_internal_file_list = []
|
_internal_file_list = []
|
||||||
_reader.close()
|
_reader.close()
|
||||||
@ -92,25 +119,6 @@ func get_files() -> PackedStringArray:
|
|||||||
ret.append(record.filename)
|
ret.append(record.filename)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
func _octal_str_to_int(s : String) -> int:
|
|
||||||
var ret : int = 0;
|
|
||||||
var digit_multiplier = 1;
|
|
||||||
while len(s):
|
|
||||||
var lsb = s.substr(len(s) - 1, 1)
|
|
||||||
s = s.substr(0, len(s) - 1)
|
|
||||||
ret += digit_multiplier * lsb.to_int()
|
|
||||||
digit_multiplier *= 8
|
|
||||||
return ret
|
|
||||||
|
|
||||||
func _pad_to_512(x : int) -> int:
|
|
||||||
var x_lowbits = x & 511
|
|
||||||
var x_hibits = x & ~511
|
|
||||||
|
|
||||||
if x_lowbits:
|
|
||||||
x_hibits += 512
|
|
||||||
|
|
||||||
return x_hibits
|
|
||||||
|
|
||||||
func open(path: String) -> Error:
|
func open(path: String) -> Error:
|
||||||
|
|
||||||
assert(not _reader)
|
assert(not _reader)
|
||||||
@ -234,10 +242,7 @@ func open(path: String) -> Error:
|
|||||||
|
|
||||||
return OK
|
return OK
|
||||||
|
|
||||||
func _load_record(record : TarFileRecord) -> PackedByteArray:
|
# Extract a file into memory as a PackedByteArray.
|
||||||
load_cache()
|
|
||||||
return _tar_file_cache.slice(record.offset, record.offset + record.file_size)
|
|
||||||
|
|
||||||
func read_file(path : String, case_sensitive : bool = true) -> PackedByteArray:
|
func read_file(path : String, case_sensitive : bool = true) -> PackedByteArray:
|
||||||
|
|
||||||
for record : TarFileRecord in _internal_file_list:
|
for record : TarFileRecord in _internal_file_list:
|
||||||
@ -250,7 +255,14 @@ func read_file(path : String, case_sensitive : bool = true) -> PackedByteArray:
|
|||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
func unpack_file(dest_path : String, filename : String):
|
# Extract a file to a specific path. Sets permissions when possible, handles
|
||||||
|
# symlinks and directories. Will extract to the dest_path plus the internal
|
||||||
|
# relative path.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# dest_path: "foo/bar", filename: "butts/whatever/thingy.txt"
|
||||||
|
# extracts to: "foo/bar/butts/whatever/thingy.txt"
|
||||||
|
func unpack_file(dest_path : String, filename : String, overwrite : bool = false):
|
||||||
var full_dest_path : String = dest_path.path_join(filename)
|
var full_dest_path : String = dest_path.path_join(filename)
|
||||||
DirAccess.make_dir_recursive_absolute(full_dest_path.get_base_dir())
|
DirAccess.make_dir_recursive_absolute(full_dest_path.get_base_dir())
|
||||||
|
|
||||||
@ -269,6 +281,12 @@ func unpack_file(dest_path : String, filename : String):
|
|||||||
# traversal attacks.
|
# traversal attacks.
|
||||||
|
|
||||||
if record.filename == filename:
|
if record.filename == filename:
|
||||||
|
|
||||||
|
# FIXME: Somehow this is slower than just overwriting the file.
|
||||||
|
# Awesome. /s
|
||||||
|
if overwrite == false and FileAccess.file_exists(full_dest_path):
|
||||||
|
continue
|
||||||
|
|
||||||
if record.is_link:
|
if record.is_link:
|
||||||
|
|
||||||
# Okay, look. I know that symbolic links technically exist on
|
# Okay, look. I know that symbolic links technically exist on
|
||||||
@ -276,24 +294,30 @@ func unpack_file(dest_path : String, filename : String):
|
|||||||
# if for some reason you need to support that. -Kiri
|
# if for some reason you need to support that. -Kiri
|
||||||
assert(OS.get_name() != "Windows")
|
assert(OS.get_name() != "Windows")
|
||||||
|
|
||||||
|
# Fire off a command to make a symbolic link on *normal* OSes.
|
||||||
var err = OS.execute("ln", [
|
var err = OS.execute("ln", [
|
||||||
"-s",
|
"-s",
|
||||||
record.link_destination,
|
record.link_destination,
|
||||||
ProjectSettings.globalize_path(full_dest_path) ])
|
ProjectSettings.globalize_path(full_dest_path)
|
||||||
|
])
|
||||||
|
|
||||||
assert(err != -1)
|
assert(err != -1)
|
||||||
|
|
||||||
elif record.is_directory:
|
elif record.is_directory:
|
||||||
|
|
||||||
|
# It's just a directory. Make it.
|
||||||
DirAccess.make_dir_recursive_absolute(full_dest_path)
|
DirAccess.make_dir_recursive_absolute(full_dest_path)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
# Okay this is an actual file. Extract it.
|
||||||
var file_data : PackedByteArray = read_file(record.filename)
|
var file_data : PackedByteArray = read_file(record.filename)
|
||||||
var out_file = FileAccess.open(full_dest_path, FileAccess.WRITE)
|
var out_file = FileAccess.open(full_dest_path, FileAccess.WRITE)
|
||||||
out_file.store_buffer(file_data)
|
out_file.store_buffer(file_data)
|
||||||
out_file.close()
|
out_file.close()
|
||||||
|
|
||||||
# Set permissions.
|
# Set permissions (on normal OSes, not Windows). I don't think this
|
||||||
|
# applies to symlinks, though.
|
||||||
if not record.is_link:
|
if not record.is_link:
|
||||||
if OS.get_name() != "Windows":
|
if OS.get_name() != "Windows":
|
||||||
var err = OS.execute("chmod", [
|
var err = OS.execute("chmod", [
|
@ -1,190 +0,0 @@
|
|||||||
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)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user