From b9d706f92b64dc003514fa31ae804564fb0af429 Mon Sep 17 00:00:00 2001 From: Ishan Gupta-AWS <74676865+ig15@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:50:20 +0530 Subject: [PATCH] Added cmake versioning feature (#165) * Added cmake versioning feature * Modified a comment --------- Co-authored-by: Ubuntu Co-authored-by: Nikhil Kamath <110539926+amazonKamath@users.noreply.github.com> --- CMakeLists.txt | 9 ++++ CMakeLists.txt.versioning | 110 ++++++++++++++++++++++++++++++++++++++ src/Version.h.in | 14 +++++ src/config/ConfigFile.cpp | 7 +++ src/config/ConfigFile.h | 1 + src/main.cpp | 11 ++-- 6 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 CMakeLists.txt.versioning create mode 100644 src/Version.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 79db672..aa4e90b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,11 +6,20 @@ project(${AWS_TUNNEL_LOCAL_PROXY_TARGET_NAME} CXX) option(BUILD_TESTS "Build tests" OFF) option(LINK_STATIC_OPENSSL "Use static openssl libs" ON) +option(GIT_VERSION "Updates the version number using the Git commit history" ON) if(BUILD_TESTS) set(AWS_TUNNEL_LOCAL_PROXY_TEST_NAME localproxytest) project(${AWS_TUNNEL_LOCAL_PROXY_TEST_NAME} CXX) endif(BUILD_TESTS) +######################################### +# Generate Version Information from Git # +######################################### +find_package(Git) +include(CMakeLists.txt.versioning) +# Now we inject the version information into a header that is accessible from the local proxy executable +configure_file("src/Version.h.in" "${PROJECT_BINARY_DIR}/Version.h") + ###################################### # Section : Disable in-source builds # ###################################### diff --git a/CMakeLists.txt.versioning b/CMakeLists.txt.versioning new file mode 100644 index 0000000..f9f09e5 --- /dev/null +++ b/CMakeLists.txt.versioning @@ -0,0 +1,110 @@ +# This CMake module is used to generate semantic version information for the AWS IoT Secure Tunneling Local Proxy +# and inject it into our source code, making the version information available to the compiled binary +# so that it can be written to the logs for debugging purposes. To increment the major/minor versions +# of the Secure Tunneling Local Proxy, this module expects to find a git tag in the form of "v1.0", where the first number +# is the major version and the second number is the minor version. This module will search starting at HEAD +# until it finds the latest versioned tag - git tags that do not start with "v" will be ignored. +# +# Additionally, the PATCH version of the version number is automatically incremented based on the number of commits +# that we see between the current revision and the latest Git tag. For more information on Semantic Versioning, +# check out https://semver.org/ and for more information on Git tags, check out https://git-scm.com/book/en/v2/Git-Basics-Tagging + +cmake_minimum_required(VERSION 3.10) + +# Marking Secure Tunneling Local Proxy directory safe +execute_process(COMMAND git config --global --add safe.directory ${CMAKE_CURRENT_SOURCE_DIR}) + +# Check to make sure we have Git info for this package +execute_process(COMMAND git log --pretty=format:'%h' -n 1 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE GIT_INFO) + +function (load_version_from_file) + # Git is not available (this is the case if the source is packaged as an archive), get version from file + file(STRINGS ${CMAKE_SOURCE_DIR}/.version ${PROJECT_NAME}_VERSION_LIST) + string(REPLACE "*" ";" ${PROJECT_NAME}_VERSION_LIST ${${PROJECT_NAME}_VERSION_LIST}) + # Set partial versions + list(GET ${PROJECT_NAME}_VERSION_LIST 0 ${PROJECT_NAME}_VERSION_STRING_FULL) + list(GET ${PROJECT_NAME}_VERSION_LIST 1 ${PROJECT_NAME}_VERSION_STRING) + list(GET ${PROJECT_NAME}_VERSION_LIST 2 ${PROJECT_NAME}_VERSION_MAJOR) + list(GET ${PROJECT_NAME}_VERSION_LIST 3 ${PROJECT_NAME}_VERSION_MINOR) + list(GET ${PROJECT_NAME}_VERSION_LIST 4 ${PROJECT_NAME}_VERSION_PATCH) + list(GET ${PROJECT_NAME}_VERSION_LIST 5 ${PROJECT_NAME}_VERSION_AHEAD) + list(GET ${PROJECT_NAME}_VERSION_LIST 6 ${PROJECT_NAME}_VERSION_GIT_SHA) + unset(${PROJECT_NAME}_VERSION_LIST) + + message("-- Failed to infer patch version from git, loaded AWS IoT Secure Tunneling Local Proxy version from file: ${${PROJECT_NAME}_VERSION_STRING_FULL}") +endfunction() + +if (GIT_VERSION AND NOT ${GIT_INFO} STREQUAL "") + message("-- Using Git to calculate AWS IoT Secure Tunneling Local Proxy version information...") + + # Get last tag from git - this only matches tags starting with v, so we ignore non-versioning tags + execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=0 --tags --match "v[0-9]*" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_STRING + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE exit) + + if (NOT exit EQUAL 0) + load_version_from_file() + return() + endif() + + # Determine how many commits since last tag + execute_process(COMMAND ${GIT_EXECUTABLE} rev-list ${${PROJECT_NAME}_VERSION_STRING}..HEAD --count + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_AHEAD + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE exit) + + if (NOT exit EQUAL 0) + load_version_from_file() + return() + endif() + + # Get current commit SHA from git + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${PROJECT_NAME}_VERSION_GIT_SHA + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE exit) + + if (NOT exit EQUAL 0) + load_version_from_file() + return() + endif() + + # Collect the partial versions into a list + string(REGEX MATCHALL "[0-9]+" ${PROJECT_NAME}_PARTIAL_VERSION_LIST + ${${PROJECT_NAME}_VERSION_STRING}) + + # Set the version numbers + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST + 0 ${PROJECT_NAME}_VERSION_MAJOR) + list(GET ${PROJECT_NAME}_PARTIAL_VERSION_LIST + 1 ${PROJECT_NAME}_VERSION_MINOR) + set(${PROJECT_NAME}_VERSION_PATCH ${${PROJECT_NAME}_VERSION_AHEAD}) + + # Unset the list + unset(${PROJECT_NAME}_PARTIAL_VERSION_LIST) + + # Set full project version string + set(${PROJECT_NAME}_VERSION_STRING_FULL + v${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}-${${PROJECT_NAME}_VERSION_GIT_SHA}) + + + message("-- Generated AWS IoT Secure Tunneling Local Proxy version: ${${PROJECT_NAME}_VERSION_STRING_FULL}") + # Save version to file (which will be used when Git is not available + # or VERSION_UPDATE_FROM_GIT is disabled) + file(WRITE ${CMAKE_SOURCE_DIR}/.version ${${PROJECT_NAME}_VERSION_STRING_FULL} + "*" ${${PROJECT_NAME}_VERSION_STRING} + "*" ${${PROJECT_NAME}_VERSION_MAJOR} + "*" ${${PROJECT_NAME}_VERSION_MINOR} + "*" ${${PROJECT_NAME}_VERSION_PATCH} + "*" ${${PROJECT_NAME}_VERSION_AHEAD} + "*" ${${PROJECT_NAME}_VERSION_GIT_SHA}) + + # exit from cmake processing + return() +endif() diff --git a/src/Version.h.in b/src/Version.h.in new file mode 100644 index 0000000..b3b1543 --- /dev/null +++ b/src/Version.h.in @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/** + * CMake will inject version information into this file at compile time, and will + * make it accessible to our source code as "Version.h" + */ +#ifndef AWS_IOT_SECURE_TUNNELING_LOCAL_PROXY_VERSION_H +#define AWS_IOT_SECURE_TUNNELING_LOCAL_PROXY_VERSION_H + +#define LOCAL_PROXY_VERSION_FULL "${${PROJECT_NAME}_VERSION_STRING_FULL}" +#define LOCAL_PROXY_VERSION "${${PROJECT_NAME}_VERSION_STRING}" + +#endif // AWS_IOT_SECURE_TUNNELING_LOCAL_PROXY_VERSION_H diff --git a/src/config/ConfigFile.cpp b/src/config/ConfigFile.cpp index 105ca10..2a3205c 100644 --- a/src/config/ConfigFile.cpp +++ b/src/config/ConfigFile.cpp @@ -28,6 +28,7 @@ #include #include "ConfigFile.h" +#include "Version.h" using std::uint16_t; using std::endl; @@ -57,6 +58,12 @@ namespace aws { namespace iot { namespace securedtunneling { namespace config_fi * @param file_dir : directory file path * @return true: valid configuration. false: invalid configuration */ + + std::string PrintVersion() + { + return LOCAL_PROXY_VERSION_FULL; + } + bool is_valid_directory(string const & file_dir) { bool is_dir = false; try { diff --git a/src/config/ConfigFile.h b/src/config/ConfigFile.h index 7053099..89fcaff 100644 --- a/src/config/ConfigFile.h +++ b/src/config/ConfigFile.h @@ -20,4 +20,5 @@ namespace aws { namespace iot { namespace securedtunneling { namespace config_fi unordered_set const & service_ids, unordered_map & serviceId_to_endpoint_mapping); void update_port_mapping(const string & cli_input, unordered_map & serviceId_to_endpoint_mapping); + std::string PrintVersion(); }}}} diff --git a/src/main.cpp b/src/main.cpp index e18856d..e4c5f8d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "TcpAdapterProxy.h" #include "config/ConfigFile.h" #include "LocalproxyConfig.h" +#include "./config/ConfigFile.h" using std::uint16_t; using std::endl; @@ -50,6 +51,7 @@ using aws::iot::securedtunneling::tcp_adapter_proxy; using aws::iot::securedtunneling::proxy_mode; using aws::iot::securedtunneling::get_region_endpoint; using aws::iot::securedtunneling::settings::apply_region_overrides; +using aws::iot::securedtunneling::config_file::PrintVersion; char const * const ACCESS_TOKEN_ENV_VARIABLE = "AWSIOT_TUNNEL_ACCESS_TOKEN"; char const * const CLIENT_TOKEN_ENV_VARIABLE = "AWSIOT_TUNNEL_CLIENT_TOKEN"; @@ -158,7 +160,7 @@ bool process_cli(int argc, char ** argv, LocalproxyConfig &cfg, ptree &settings, options_description cliargs_desc("Allowed options"); cliargs_desc.add_options() ("help,h", "Show help message") - ("version", "Show version") + ("version", "Show current version of Local Proxy") ("access-token,t", value()->required(), "Client access token") ("client-token,i", value(), "Optional Client Token") ("proxy-endpoint,e", value(), "Endpoint of proxy server with port (if not default 443). Example: data.tunneling.iot.us-east-1.amazonaws.com:443") @@ -180,8 +182,7 @@ bool process_cli(int argc, char ** argv, LocalproxyConfig &cfg, ptree &settings, if (vm.count("version")) { - std::cerr << "3.1.2" << "\n"; // hardcoding this as a temporary measure - return false; + PrintVersion(); } if (vm.count("help")) { @@ -431,6 +432,10 @@ int main(int argc, char ** argv) { try { + + std::string version = PrintVersion(); + std::cout << "Running AWS IoT Secure Tunneling Local Proxy version: " << version << std::endl; + LocalproxyConfig cfg; ptree settings; std::uint16_t logging_level;