You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
6.6 KiB

6 months ago
@tool
extends Node
## Script that checks for new versions and can install them.
signal update_check_completed(result:UpdateCheckResult)
signal downdload_completed(result:DownloadResult)
enum UpdateCheckResult {UPDATE_AVAILABLE, UP_TO_DATE, NO_ACCESS}
enum DownloadResult {SUCCESS, FAILURE}
enum ReleaseState {ALPHA, BETA, STABLE}
const REMOTE_RELEASES_URL := "https://api.github.com/repos/dialogic-godot/dialogic/releases"
const TEMP_FILE_NAME = "user://temp.zip"
var current_version : String = ""
var update_info: Dictionary
var current_info: Dictionary
var version_indicator :Button
func _ready() -> void:
request_update_check()
setup_version_indicator()
func get_current_version() -> String:
var plugin_cfg := ConfigFile.new()
plugin_cfg.load("res://addons/dialogic/plugin.cfg")
return plugin_cfg.get_value('plugin', 'version', 'unknown version')
func request_update_check() -> void:
if $UpdateCheckRequest.get_http_client_status() == HTTPClient.STATUS_DISCONNECTED:
$UpdateCheckRequest.request(REMOTE_RELEASES_URL)
func _on_UpdateCheck_request_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray) -> void:
if result != HTTPRequest.RESULT_SUCCESS:
update_check_completed.emit(UpdateCheckResult.NO_ACCESS)
return
# Work out the next version from the releases information on GitHub
var response :Variant= JSON.parse_string(body.get_string_from_utf8())
if typeof(response) != TYPE_ARRAY: return
var current_release_info := get_release_tag_info(get_current_version())
# GitHub releases are in order of creation, not order of version
var versions :Array = (response as Array).filter(compare_versions.bind(current_release_info))
if versions.size() > 0:
update_info = versions[0]
update_check_completed.emit(UpdateCheckResult.UPDATE_AVAILABLE)
else:
update_info = current_info
update_check_completed.emit(UpdateCheckResult.UP_TO_DATE)
func compare_versions(release, current_release_info:Dictionary) -> bool:
var checked_release_info := get_release_tag_info(release.tag_name)
if checked_release_info.major < current_release_info.major:
return false
if checked_release_info.minor < current_release_info.minor:
return false
if checked_release_info.state < current_release_info.state:
return false
elif checked_release_info.state == current_release_info.state:
if checked_release_info.state_version < current_release_info.state_version:
return false
if checked_release_info.state_version == current_release_info.state_version:
current_info = release
return false
if checked_release_info.state == ReleaseState.STABLE:
if checked_release_info.minor == current_release_info.minor:
current_info = release
return false
return true
func get_release_tag_info(release_tag:String) -> Dictionary:
release_tag = release_tag.strip_edges().trim_prefix('v')
release_tag = release_tag.substr(0, release_tag.find('('))
release_tag = release_tag.to_lower()
var regex := RegEx.create_from_string('(?<major>\\d+\\.\\d+)(-(?<state>alpha|beta)-)?(?(2)(?<stateversion>\\d*)|\\.(?<minor>\\d*))?')
var result: RegExMatch = regex.search(release_tag)
if !result:
return {}
var info:Dictionary = {'tag':release_tag}
info['major'] = float(result.get_string('major'))
info['minor'] = int(result.get_string('minor'))
match result.get_string('state'):
'alpha':
info['state'] = ReleaseState.ALPHA
'beta':
info['state'] = ReleaseState.BETA
_:
info['state'] = ReleaseState.STABLE
info['state_version'] = int(result.get_string('stateversion'))
return info
func request_update_download() -> void:
# Safeguard the actual dialogue manager repo from accidentally updating itself
if DirAccess.dir_exists_absolute("res://test-project/"):
prints("[Dialogic] Looks like you are working on the addon. You can't update the addon from within itself.")
downdload_completed.emit(DownloadResult.FAILURE)
return
$DownloadRequest.request(update_info.zipball_url)
func _on_DownloadRequest_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray):
if result != HTTPRequest.RESULT_SUCCESS:
downdload_completed.emit(DownloadResult.FAILURE)
return
# Save the downloaded zip
var zip_file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE)
zip_file.store_buffer(body)
zip_file.close()
OS.move_to_trash(ProjectSettings.globalize_path("res://addons/dialogic"))
var zip_reader: ZIPReader = ZIPReader.new()
zip_reader.open(TEMP_FILE_NAME)
var files: PackedStringArray = zip_reader.get_files()
var base_path = files[0].path_join('addons/')
for path in files:
if not "dialogic/" in path:
continue
var new_file_path: String = path.replace(base_path, "")
if path.ends_with("/"):
DirAccess.make_dir_recursive_absolute("res://addons/".path_join(new_file_path))
else:
var file: FileAccess = FileAccess.open("res://addons/".path_join(new_file_path), FileAccess.WRITE)
file.store_buffer(zip_reader.read_file(path))
zip_reader.close()
DirAccess.remove_absolute(TEMP_FILE_NAME)
downdload_completed.emit(DownloadResult.SUCCESS)
###################### SOME UI MANAGEMENT #####################################
################################################################################
func setup_version_indicator():
version_indicator = %Sidebar.get_node('%CurrentVersion')
version_indicator.pressed.connect($Window/UpdateInstallWindow.open)
version_indicator.text = get_current_version()
func _on_update_check_completed(result:int):
var result_color : Color
match result:
UpdateCheckResult.UPDATE_AVAILABLE:
result_color = version_indicator.get_theme_color("warning_color", "Editor")
version_indicator.icon = version_indicator.get_theme_icon("StatusWarning", "EditorIcons")
$Window/UpdateInstallWindow.load_info(update_info, result)
UpdateCheckResult.UP_TO_DATE:
result_color = version_indicator.get_theme_color("success_color", "Editor")
version_indicator.icon = version_indicator.get_theme_icon("StatusSuccess", "EditorIcons")
$Window/UpdateInstallWindow.load_info(current_info, result)
UpdateCheckResult.NO_ACCESS:
result_color = version_indicator.get_theme_color("success_color", "Editor")
version_indicator.icon = version_indicator.get_theme_icon("GuiRadioCheckedDisabled", "EditorIcons")
$Window/UpdateInstallWindow.load_info(update_info, result)
version_indicator.add_theme_color_override('font_color', result_color)
version_indicator.add_theme_color_override('font_hover_color', result_color.lightened(0.5))
version_indicator.add_theme_color_override('font_pressed_color', result_color)
version_indicator.add_theme_color_override('font_focus_color', result_color)