hook up downloading releases and templates to component

This commit is contained in:
Lera Elvoé 2023-05-25 23:13:07 +03:00
parent 94c256b608
commit db5700b62d
Signed by: yagich
SSH Key Fingerprint: SHA256:6xjGb6uA7lAVcULa7byPEN//rQ0wPoG+UzYVMfZnbvc
4 changed files with 131 additions and 19 deletions

View File

@ -21,22 +21,55 @@ var threads: Array[Thread]
signal releases_fetched(releases: Releases) signal releases_fetched(releases: Releases)
signal version_downloaded(version: String) signal version_downloaded(version: String)
signal export_templates_downloaded(version: String) signal export_templates_downloaded(version: String)
signal status_update(status: String)
enum Status{
IDLE,
RELEASE_DOWNLOAD_IN_PROGRESS,
TEMPLATE_DOWNLOAD_IN_PROGRESS,
DOWNLOAD_DONE,
FETCHING_RELEASES,
FETCHING_DONE,
VERSION_NOT_IN_INDEX,
RELEASE_ALREADY_EXISTS,
TEMPLATE_ALREADY_EXISTS,
UNPACKING_TEMPLATES,
UNPACKING_RELEASE,
RELEASE_INSTALLED,
TEMPLATE_INSTALLED,
}
const STATUS_MESSAGES := {
Status.IDLE: "Idle",
Status.RELEASE_DOWNLOAD_IN_PROGRESS: "Downloading Godot v%s",
Status.TEMPLATE_DOWNLOAD_IN_PROGRESS: "Downloading Export Templates for v%s",
Status.DOWNLOAD_DONE: "Done downloading",
Status.FETCHING_RELEASES: "Fetching releases",
Status.FETCHING_DONE: "Done fetching releases",
Status.VERSION_NOT_IN_INDEX: "Version not in index. Fetch first",
Status.RELEASE_ALREADY_EXISTS: "This version already exists",
Status.TEMPLATE_ALREADY_EXISTS: "Templates for this version already exist",
Status.UNPACKING_TEMPLATES: "Unpacking Export Templates for v%s",
Status.UNPACKING_RELEASE: "Unpacking Godot v%s",
Status.RELEASE_INSTALLED: "Godot v%s installed",
Status.TEMPLATE_INSTALLED: "Export Templates for Godot v%s installed",
}
func _ready() -> void: func _ready() -> void:
DirAccess.make_dir_absolute(TEMP_FOLDER) DirAccess.make_dir_absolute(TEMP_FOLDER)
DirAccess.make_dir_absolute(RELEASES_BASE_FOLDER) DirAccess.make_dir_absolute(RELEASES_BASE_FOLDER)
add_child(http) add_child(http)
releases = load_releases() releases = load_releases()
clean_tmp()
func fetch_releases(force_local: bool = false) -> void: func fetch_releases(force_local: bool = false) -> void:
if force_local: if force_local && FileAccess.file_exists(RELEASES_FILE):
releases_fetched.emit(releases) releases_fetched.emit(releases)
return return
if is_downloading: if is_downloading:
print("downloading something, try again later") print("Another download is in progress, try again later")
return return
if releases.last_checked_at + FETCH_COOLDOWN > Time.get_unix_time_from_system(): if releases.last_checked_at + FETCH_COOLDOWN > Time.get_unix_time_from_system():
@ -82,7 +115,8 @@ func fetch_releases(force_local: bool = false) -> void:
if rm.is_empty(): if rm.is_empty():
releases.releases.erase(i.tag_name) releases.releases.erase(i.tag_name)
releases_fetched.emit() releases_fetched.emit(releases)
status_update.emit(STATUS_MESSAGES[Status.FETCHING_DONE])
is_downloading = false is_downloading = false
save_releases() save_releases()
@ -92,6 +126,7 @@ func fetch_releases(force_local: bool = false) -> void:
"X-GitHub-Api-Version: 2022-11-28", "X-GitHub-Api-Version: 2022-11-28",
] ]
is_downloading = true is_downloading = true
status_update.emit(STATUS_MESSAGES[Status.FETCHING_RELEASES])
http.request(API_SLUG + RELEASES_SLUG, PackedStringArray(headers)) http.request(API_SLUG + RELEASES_SLUG, PackedStringArray(headers))
http.request_completed.connect(response_func, CONNECT_ONE_SHOT) http.request_completed.connect(response_func, CONNECT_ONE_SHOT)
@ -102,11 +137,13 @@ func download_release(version: String) -> void:
return return
if !releases.releases.has(version): if !releases.releases.has(version):
print("this version is not in the index yet or does not exist. fetch first") # print("this version is not in the index yet or does not exist. fetch first")
status_update.emit(STATUS_MESSAGES[Status.VERSION_NOT_IN_INDEX])
return return
if (releases.releases[version] as ReleaseMetadata).binary_path != "": if (releases.releases[version] as ReleaseMetadata).binary_path != "":
print("already have this version") # print("already have this version")
status_update.emit(STATUS_MESSAGES[Status.RELEASE_ALREADY_EXISTS])
return return
var rm: ReleaseMetadata = releases.releases[version] var rm: ReleaseMetadata = releases.releases[version]
@ -114,6 +151,7 @@ func download_release(version: String) -> void:
if response_code == 200: if response_code == 200:
# download happens in place. # download happens in place.
# we know the file is zip, so save it to temp first before unpacking # we know the file is zip, so save it to temp first before unpacking
status_update.emit(STATUS_MESSAGES[Status.DOWNLOAD_DONE])
print("got it in place") print("got it in place")
print("downloading url: ", rm.binary_github_filename) print("downloading url: ", rm.binary_github_filename)
var zip_filename := TEMP_FOLDER.path_join("%s.zip" % version) var zip_filename := TEMP_FOLDER.path_join("%s.zip" % version)
@ -132,7 +170,8 @@ func download_release(version: String) -> void:
return return
var res := zip.read_file(filename.trim_suffix(".zip")) var res := zip.read_file(filename.trim_suffix(".zip"))
zip.close() zip.close()
# clean_tmp() clean_tmp()
status_update.emit(STATUS_MESSAGES[Status.UNPACKING_RELEASE] % version)
var d := DirAccess.open(RELEASES_BASE_FOLDER) var d := DirAccess.open(RELEASES_BASE_FOLDER)
d.make_dir_recursive(version) d.make_dir_recursive(version)
var new_file := RELEASES_BASE_FOLDER.path_join(version) var new_file := RELEASES_BASE_FOLDER.path_join(version)
@ -142,6 +181,7 @@ func download_release(version: String) -> void:
f.close() f.close()
rm.binary_path = new_file rm.binary_path = new_file
version_downloaded.emit(version) version_downloaded.emit(version)
status_update.emit(STATUS_MESSAGES[Status.RELEASE_INSTALLED] % version)
is_downloading = false is_downloading = false
save_releases() save_releases()
@ -155,6 +195,7 @@ func download_release(version: String) -> void:
"X-GitHub-Api-Version: 2022-11-28", "X-GitHub-Api-Version: 2022-11-28",
] ]
var asset_url = API_SLUG.path_join(RELEASES_SLUG).path_join(ASSET_SLUG) % rm.binary_github_asset_id var asset_url = API_SLUG.path_join(RELEASES_SLUG).path_join(ASSET_SLUG) % rm.binary_github_asset_id
status_update.emit(STATUS_MESSAGES[Status.RELEASE_DOWNLOAD_IN_PROGRESS] % version)
is_downloading = true is_downloading = true
http.request(asset_url, PackedStringArray(headers)) http.request(asset_url, PackedStringArray(headers))
http.request_completed.connect(response_func.bind(rm.binary_github_filename), CONNECT_ONE_SHOT) http.request_completed.connect(response_func.bind(rm.binary_github_filename), CONNECT_ONE_SHOT)
@ -166,16 +207,19 @@ func download_export_templates(version: String) -> void:
return return
if !releases.releases.has(version): if !releases.releases.has(version):
print("this version is not in the index yet or does not exist. fetch first") # print("this version is not in the index yet or does not exist. fetch first")
status_update.emit(STATUS_MESSAGES[Status.VERSION_NOT_IN_INDEX])
return return
if (releases.releases[version] as ReleaseMetadata).export_templates_path != "": if (releases.releases[version] as ReleaseMetadata).export_templates_path != "":
print("already have templates for this version") # print("already have templates for this version")
status_update.emit(STATUS_MESSAGES[Status.TEMPLATE_ALREADY_EXISTS])
return return
var rm: ReleaseMetadata = releases.releases[version] var rm: ReleaseMetadata = releases.releases[version]
var response_func = func(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray): var response_func = func(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray):
if response_code == 200: if response_code == 200:
status_update.emit(STATUS_MESSAGES[Status.DOWNLOAD_DONE])
print("got it in place") print("got it in place")
print("downloading url: ", rm.export_github_filename) print("downloading url: ", rm.export_github_filename)
var zip_filename := TEMP_FOLDER.path_join("%s_export.tpz" % version) var zip_filename := TEMP_FOLDER.path_join("%s_export.tpz" % version)
@ -196,10 +240,11 @@ func download_export_templates(version: String) -> void:
var d := DirAccess.open(RELEASES_BASE_FOLDER) var d := DirAccess.open(RELEASES_BASE_FOLDER)
d.make_dir_recursive(version.path_join("templates")) d.make_dir_recursive(version.path_join("templates"))
var templates_folder := RELEASES_BASE_FOLDER.path_join(version) var templates_folder := RELEASES_BASE_FOLDER.path_join(version)
status_update.emit(STATUS_MESSAGES[Status.UNPACKING_TEMPLATES] % version)
for file in files: for file in files:
var t := Thread.new() var t := Thread.new()
threads.append(t) threads.append(t)
t.start(unpack_zip_file.bind(zip_filename, file, templates_folder.path_join(file), t)) t.start(unpack_zip_file.bind(zip_filename, file, templates_folder.path_join(file), t, version))
zip.close() zip.close()
# don't clean tmp just yet, since there might be other threads # don't clean tmp just yet, since there might be other threads
@ -220,12 +265,13 @@ func download_export_templates(version: String) -> void:
"X-GitHub-Api-Version: 2022-11-28", "X-GitHub-Api-Version: 2022-11-28",
] ]
var asset_url = API_SLUG.path_join(RELEASES_SLUG).path_join(ASSET_SLUG) % rm.export_github_asset_id var asset_url = API_SLUG.path_join(RELEASES_SLUG).path_join(ASSET_SLUG) % rm.export_github_asset_id
status_update.emit(STATUS_MESSAGES[Status.TEMPLATE_DOWNLOAD_IN_PROGRESS] % version)
is_downloading = true is_downloading = true
http.request(asset_url, PackedStringArray(headers)) http.request(asset_url, PackedStringArray(headers))
http.request_completed.connect(response_func, CONNECT_ONE_SHOT) http.request_completed.connect(response_func, CONNECT_ONE_SHOT)
func unpack_zip_file(zip_file: String, from_file: String, dest_file: String, thread: Thread) -> void: func unpack_zip_file(zip_file: String, from_file: String, dest_file: String, thread: Thread, version: String) -> void:
print("extracting file ", from_file, " to: ", dest_file) print("extracting file ", from_file, " to: ", dest_file)
var z := ZIPReader.new() var z := ZIPReader.new()
var f := z.open(zip_file) var f := z.open(zip_file)
@ -239,14 +285,15 @@ func unpack_zip_file(zip_file: String, from_file: String, dest_file: String, thr
file.close() file.close()
z.close() z.close()
_clean_threads.call_deferred(thread) _clean_threads.call_deferred(thread, version)
func _clean_threads(thread: Thread) -> void: func _clean_threads(thread: Thread, version: String) -> void:
threads.erase(thread) threads.erase(thread)
thread.wait_to_finish() thread.wait_to_finish()
if threads.is_empty(): if threads.is_empty():
status_update.emit(STATUS_MESSAGES[Status.TEMPLATE_INSTALLED] % version)
clean_tmp() clean_tmp()
@ -274,6 +321,14 @@ func get_version_metadata(version: String) -> ReleaseMetadata:
return releases.releases.get(version) return releases.releases.get(version)
func get_installed_versions() -> Array[ReleaseMetadata]:
var res: Array[ReleaseMetadata] = []
for version in releases.releases:
if is_version_installed(version):
res.append(releases.releases[version])
return res
func clean_tmp() -> void: func clean_tmp() -> void:
var d := DirAccess.open(TEMP_FOLDER) var d := DirAccess.open(TEMP_FOLDER)
if !d: if !d:

View File

@ -7,18 +7,18 @@ class_name ReleaseItem
var version: String var version: String
signal install_button_pressed signal install_button_pressed(version)
signal install_templates_button_pressed signal install_templates_button_pressed(version)
func _ready() -> void: func _ready() -> void:
install_button.pressed.connect(func(): install_button_pressed.emit()) install_button.pressed.connect(func(): install_button_pressed.emit(version))
install_templates_button.pressed.connect(func(): install_templates_button_pressed.emit()) install_templates_button.pressed.connect(func(): install_templates_button_pressed.emit(version))
func set_version(v: String) -> void: func set_version(v: String) -> void:
version = v version = v
version_label.text = v version_label.text = "Godot v%s" % v
func set_install_button_disabled(d: bool) -> void: func set_install_button_disabled(d: bool) -> void:
@ -27,3 +27,21 @@ func set_install_button_disabled(d: bool) -> void:
func set_templates_button_disabled(d: bool) -> void: func set_templates_button_disabled(d: bool) -> void:
install_templates_button.disabled = d install_templates_button.disabled = d
func _on_version_downloaded(p_version: String) -> void:
if p_version != version:
# this isn't us
return
set_install_button_disabled(true)
ReleasesManager.version_downloaded.disconnect(_on_version_downloaded)
func _on_export_templates_downloaded(p_version: String) -> void:
if p_version != version:
# this isn't us
return
set_templates_button_disabled(true)
ReleasesManager.export_templates_downloaded.disconnect(_on_export_templates_downloaded)

View File

@ -1,3 +1,43 @@
extends VBoxContainer extends VBoxContainer
const ITEM_SCENE := preload("res://UI/Components/ReleaseItem.tscn") const ITEM_SCENE := preload("res://UI/Components/ReleaseItem.tscn")
@onready var release_items_container: VBoxContainer = %ReleaseItemsContainer
@onready var fetch_button: Button = %FetchButton
@onready var status_label: Label = %StatusLabel
func _ready() -> void:
ReleasesManager.releases_fetched.connect(releases_updated)
ReleasesManager.releases_fetched.connect(func(_x):
await get_tree().process_frame
fetch_button.disabled = false
)
fetch_button.pressed.connect(func():
ReleasesManager.fetch_releases()
fetch_button.disabled = true
)
ReleasesManager.fetch_releases(true)
ReleasesManager.status_update.connect(status_label.set_text)
func releases_updated(releases: ReleasesManager.Releases) -> void:
clear_releases()
for version in releases.releases:
var item: ReleaseItem = ITEM_SCENE.instantiate()
release_items_container.add_child(item)
item.set_version(version)
item.set_install_button_disabled(ReleasesManager.is_version_installed(version))
item.set_templates_button_disabled(ReleasesManager.is_version_templates_installed(version))
item.install_button_pressed.connect(ReleasesManager.download_release)
item.install_templates_button_pressed.connect(ReleasesManager.download_release)
ReleasesManager.version_downloaded.connect(item._on_version_downloaded)
ReleasesManager.export_templates_downloaded.connect(item._on_export_templates_downloaded)
func clear_releases() -> void:
for i in release_items_container.get_children():
i.queue_free()

View File

@ -46,6 +46,5 @@ alignment = 2
[node name="StatusLabel" type="Label" parent="HBoxContainer/HBoxContainer"] [node name="StatusLabel" type="Label" parent="HBoxContainer/HBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false
layout_mode = 2 layout_mode = 2
text = "Downloading v..." text = "Idle"