From 67e9ccdbc4909b975099ea73fc5ca92a28ce1e6a Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 12 Mar 2022 02:04:14 +0100 Subject: [PATCH] Display the build date in the editor and when starting the engine This can be used to quickly see how recent a development build is, without having to look up the commit date manually. When juggling around with various builds (e.g. for benchmarking), this can also be used to ensure that you're actually running the binary you intended to run. The date stored is the date of the Git commit that is built, not the current date at the time of building the binary. This ensures binaries can remain reproducible. The version timestamp can be accessed using the `timestamp` key of the `Engine.get_version_info()` return value. --- core/config/engine.cpp | 2 ++ core/version.h | 6 ++++++ doc/classes/Engine.xml | 3 ++- editor/editor_about.cpp | 10 +++++++++- editor/gui/editor_bottom_panel.cpp | 9 ++++++++- editor/project_manager.cpp | 9 ++++++++- main/main.cpp | 23 ++++++++++++++++++++--- main/main.h | 1 + methods.py | 13 +++++++++++++ 9 files changed, 69 insertions(+), 7 deletions(-) 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 )