diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 2bb88378491..d714ec42c2c 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -114,6 +114,8 @@ Dictionary Engine::get_version_info() const { String hash = String(VERSION_HASH); dict["hash"] = hash.is_empty() ? String("unknown") : hash; + dict["timestamp"] = VERSION_TIMESTAMP; + String stringver = String(dict["major"]) + "." + String(dict["minor"]); if ((int)dict["patch"] != 0) { stringver += "." + String(dict["patch"]); diff --git a/core/version.h b/core/version.h index abb81312ac9..18a97cadf0d 100644 --- a/core/version.h +++ b/core/version.h @@ -33,6 +33,8 @@ #include "core/version_generated.gen.h" +#include + // Copied from typedefs.h to stay lean. #ifndef _STR #define _STR(m_x) #m_x @@ -77,4 +79,8 @@ // Git commit hash, generated at build time in `core/version_hash.gen.cpp`. extern const char *const VERSION_HASH; +// Git commit date UNIX timestamp (in seconds), generated at build time in `core/version_hash.gen.cpp`. +// Set to 0 if unknown. +extern const uint64_t VERSION_TIMESTAMP; + #endif // VERSION_H diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index f9c9b72ed73..4c8859baf23 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -180,6 +180,7 @@ - [code]status[/code] - Status (such as "beta", "rc1", "rc2", "stable", etc.) as a String; - [code]build[/code] - Build name (e.g. "custom_build") as a String; - [code]hash[/code] - Full Git commit hash as a String; + - [code]timestamp[/code] - Holds the Git commit date UNIX timestamp in seconds as an int, or [code]0[/code] if unavailable; - [code]string[/code] - [code]major[/code], [code]minor[/code], [code]patch[/code], [code]status[/code], and [code]build[/code] in a single String. The [code]hex[/code] value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. [b]Note:[/b] The [code]hex[/code] value is still an [int] internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for quick version comparisons from code: @@ -261,7 +262,7 @@ func _enter_tree(): # Depending on when the node is added to the tree, # prints either "true" or "false". - print(Engine.is_in_physics_frame()) + print(Engine.is_in_physics_frame()) func _process(delta): print(Engine.is_in_physics_frame()) # Prints false diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index b4ef0f8c4a7..e594d53d696 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -33,6 +33,7 @@ #include "core/authors.gen.h" #include "core/donors.gen.h" #include "core/license.gen.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/editor_string_names.h" #include "editor/themes/editor_scale.h" @@ -206,7 +207,14 @@ EditorAbout::EditorAbout() { // Set the text to copy in metadata as it slightly differs from the button's text. version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version number."), build_date)); + version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed)); version_info_vbc->add_child(version_btn); diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp index 1cf9daa5459..ab7e05b915b 100644 --- a/editor/gui/editor_bottom_panel.cpp +++ b/editor/gui/editor_bottom_panel.cpp @@ -30,6 +30,7 @@ #include "editor_bottom_panel.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_about.h" @@ -253,7 +254,13 @@ EditorBottomPanel::EditorBottomPanel() { // Fade out the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.65)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version information."), build_date)); version_btn->connect("pressed", callable_mp(this, &EditorBottomPanel::_version_button_pressed)); version_info_vbox->add_child(version_btn); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 6f7d571792f..4187bf5a325 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -38,6 +38,7 @@ #include "core/io/stream_peer_tls.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/editor_about.h" #include "editor/editor_settings.h" @@ -1350,7 +1351,13 @@ ProjectManager::ProjectManager() { // Fade the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.6)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy the version information.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version information."), build_date)); version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed)); footer_bar->add_child(version_btn); } diff --git a/main/main.cpp b/main/main.cpp index c520ebecd37..91ccbe67667 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -393,6 +393,23 @@ void finalize_theme_db() { #define MAIN_PRINT(m_txt) #endif +void Main::print_header(bool p_rich) { + if (VERSION_TIMESTAMP > 0) { + // Version timestamp available. + if (p_rich) { + print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - \u001b[4m" + String(VERSION_WEBSITE)); + } else { + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - " + String(VERSION_WEBSITE)); + } + } else { + if (p_rich) { + print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE)); + } else { + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + } + } +} + /** * Prints a copyright notice in the command-line help with colored text. A newline is * automatically added at the end. @@ -463,7 +480,7 @@ void Main::print_help_option(const char *p_option, const char *p_description, CL } void Main::print_help(const char *p_binary) { - print_line("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE) + "\u001b[0m"); + print_header(true); print_help_copyright("Free and open source software under the terms of the MIT license."); print_help_copyright("(c) 2014-present Godot Engine contributors. (c) 2007-present Juan Linietsky, Ariel Manzur."); @@ -2468,8 +2485,8 @@ Error Main::setup2() { Thread::make_main_thread(); // Make whatever thread call this the main thread. set_current_thread_safe_for_nodes(true); - // Print engine name and version - Engine::get_singleton()->print_header(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + // Don't use rich formatting to prevent ANSI escape codes from being written to log files. + print_header(false); #ifdef TOOLS_ENABLED if (editor || project_manager || cmdline_tool) { diff --git a/main/main.h b/main/main.h index 09cc0feae6f..062af73d577 100644 --- a/main/main.h +++ b/main/main.h @@ -46,6 +46,7 @@ class Main { CLI_OPTION_AVAILABILITY_HIDDEN, }; + static void print_header(bool p_rich); static void print_help_copyright(const char *p_notice); static void print_help_title(const char *p_title); static void print_help_option(const char *p_option, const char *p_description, CLIOptionAvailability p_availability = CLI_OPTION_AVAILABILITY_TEMPLATE_RELEASE); diff --git a/methods.py b/methods.py index 69d8df1d72f..c85e6825da9 100644 --- a/methods.py +++ b/methods.py @@ -209,6 +209,18 @@ def get_version_info(module_version_string="", silent=False): githash = head version_info["git_hash"] = githash + # Fallback to 0 as a timestamp (will be treated as "unknown" in the engine). + version_info["git_timestamp"] = 0 + + # Get the UNIX timestamp of the build commit. + if os.path.exists(".git"): + try: + version_info["git_timestamp"] = subprocess.check_output( + ["git", "log", "-1", "--pretty=format:%ct", githash] + ).decode("utf-8") + except (subprocess.CalledProcessError, OSError): + # `git` not found in PATH. + pass return version_info @@ -246,6 +258,7 @@ def generate_version_header(module_version_string=""): """/* THIS FILE IS GENERATED DO NOT EDIT */ #include "core/version.h" const char *const VERSION_HASH = "{git_hash}"; +const uint64_t VERSION_TIMESTAMP = {git_timestamp}; """.format( **version_info )