diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dd33357..185dacd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,8 @@ jobs: - name: Setup Python Environment shell: pwsh run: | - pip install geopandas + pip install geopandas ` + GitPython - name: Install Conan Packages shell: pwsh diff --git a/CMakeLists.txt b/CMakeLists.txt index 04f208a9..932f8513 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ conan_basic_setup(TARGETS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_NO_LIB") set(SCWX_DIR ${PROJECT_SOURCE_DIR}) +set(SCWX_VERSION "0.0.1") option(BUILD_DOCS "Build documentation" OFF) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 844254f3..0f9c5bb8 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -215,6 +215,10 @@ set(ZONE_DBF_FILES ${SCWX_DIR}/data/db/fz13se22.dbf ${SCWX_DIR}/data/db/z_13se22.dbf) set(COUNTIES_SQLITE_DB ${scwx-qt_BINARY_DIR}/res/db/counties.db) +set(VERSIONS_INPUT ${scwx-qt_SOURCE_DIR}/source/scwx/qt/main/versions.hpp.in) +set(VERSIONS_CACHE ${scwx-qt_BINARY_DIR}/versions_cache.json) +set(VERSIONS_HEADER ${scwx-qt_BINARY_DIR}/scwx/qt/main/versions.hpp) + set(PROJECT_SOURCES ${HDR_MAIN} ${SRC_MAIN} ${HDR_CONFIG} @@ -301,6 +305,21 @@ add_custom_target(scwx-qt_generate_counties_db ALL add_dependencies(scwx-qt scwx-qt_generate_counties_db) +add_custom_command(OUTPUT ${VERSIONS_HEADER} + COMMAND ${Python_EXECUTABLE} + ${scwx-qt_SOURCE_DIR}/tools/generate_versions.py + -g ${SCWX_DIR} + -v ${SCWX_VERSION} + -c ${VERSIONS_CACHE} + -i ${VERSIONS_INPUT} + -o ${VERSIONS_HEADER} + DEPENDS ${VERSIONS_INPUT}) + +add_custom_target(scwx-qt_generate_versions ALL + DEPENDS ${VERSIONS_HEADER}) + +add_dependencies(scwx-qt scwx-qt_generate_versions) + qt_add_resources(scwx-qt "generated" PREFIX "/" BASE ${scwx-qt_BINARY_DIR} @@ -317,6 +336,7 @@ set_target_properties(scwx-qt_other_files PROPERTIES FOLDER qt) set_target_properties(update_translations PROPERTIES FOLDER qt) set_target_properties(scwx-qt_generate_counties_db PROPERTIES FOLDER generate) +set_target_properties(scwx-qt_generate_versions PROPERTIES FOLDER generate) if (WIN32) set(APP_ICON_RESOURCE_WINDOWS "${scwx-qt_SOURCE_DIR}/res/scwx-qt.rc") diff --git a/scwx-qt/source/scwx/qt/main/versions.hpp.in b/scwx-qt/source/scwx/qt/main/versions.hpp.in new file mode 100644 index 00000000..32a69c59 --- /dev/null +++ b/scwx-qt/source/scwx/qt/main/versions.hpp.in @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace main +{ + +const std::string kCommitString_ {"${commit_string}"}; +const std::uint16_t kCopyrightYear_ {${copyright_year}u}; +const std::string kVersionString_ {"${version_string}"}; + +} // namespace main +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/about_dialog.cpp b/scwx-qt/source/scwx/qt/ui/about_dialog.cpp index 6e7be3e1..a42be06f 100644 --- a/scwx-qt/source/scwx/qt/ui/about_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/about_dialog.cpp @@ -1,5 +1,6 @@ #include "about_dialog.hpp" #include "ui_about_dialog.h" +#include #include #include @@ -31,6 +32,28 @@ AboutDialog::AboutDialog(QWidget* parent) : QFontDatabase::applicationFontFamilies(titleFontId).at(0); QFont titleFont(titleFontFamily, 14); ui->titleLabel->setFont(titleFont); + + QString repositoryUrl = + QString("https://github.com/dpaulat/supercell-wx/tree/%1") + .arg(QString::fromStdString(main::kCommitString_)); + + // Remove +dirty from the URL + qsizetype delimiter = repositoryUrl.indexOf('+'); + if (delimiter != -1) + { + repositoryUrl = repositoryUrl.left(delimiter); + } + + ui->versionLabel->setText( + tr("Version %1").arg(QString::fromStdString(main::kVersionString_))); + ui->revisionLabel->setText( + tr("Git Revision %2") + .arg(repositoryUrl) + .arg(QString::fromStdString(main::kCommitString_))); + ui->copyrightLabel->setText( + tr("Copyright \302\251 2021-%1 Dan Paulat").arg(main::kCopyrightYear_)); + + ui->revisionLabel->setOpenExternalLinks(true); } AboutDialog::~AboutDialog() diff --git a/scwx-qt/tools/generate_versions.py b/scwx-qt/tools/generate_versions.py new file mode 100644 index 00000000..e7c470ef --- /dev/null +++ b/scwx-qt/tools/generate_versions.py @@ -0,0 +1,157 @@ +import argparse +import datetime +import git +import json +import os +import pathlib + +class Keys: + CommitString = "commit_string" + CopyrightYear = "copyright_year" + VersionString = "version_string" + +class VersionInfo: + def __init__(self): + self.commitString_ = None + self.copyrightYear_ = None + self.versionString_ = None + + def __eq__(self, other): + if isinstance(other, VersionInfo): + return self.commitString_ == other.commitString_ and \ + self.copyrightYear_ == other.copyrightYear_ and \ + self.versionString_ == other.versionString_ + + def Value(self, key): + match key: + case Keys.CommitString: + return self.commitString_ + case Keys.CopyrightYear: + return self.copyrightYear_ + case Keys.VersionString: + return self.versionString_ + case _: + return None + +kKeys_ = [Keys.CommitString, Keys.CopyrightYear, Keys.VersionString] + +def ParseArguments(): + parser = argparse.ArgumentParser(description='Generate versions') + parser.add_argument("-c", "--cache", + metavar = "filename", + help = "cache file", + dest = "cache_", + default = None, + type = pathlib.Path) + parser.add_argument("-g", "--git-repo", + metavar = "path", + help = "base git repository path", + dest = "gitRepo_", + default = os.getcwd(), + type = pathlib.Path) + parser.add_argument("-i", "--input_header", + metavar = "filename", + help = "input header template", + dest = "inputHeader_", + type = pathlib.Path, + required = True) + parser.add_argument("-o", "--output_header", + metavar = "filename", + help = "output header", + dest = "outputHeader_", + type = pathlib.Path, + required = True) + parser.add_argument("-v", "--version", + metavar = "version", + help = "version string", + dest = "version_", + type = str, + required = True) + return parser.parse_args() + +def CollectVersionInfo(args): + print("Collecting version info") + + versionInfo = VersionInfo() + + repo = git.Repo(args.gitRepo_, search_parent_directories = True) + + commitString = str(repo.head.commit)[:10] + + if not repo.is_dirty(submodules = False): + copyrightYear = datetime.datetime.fromtimestamp(repo.head.commit.committed_date).year + else: + commitString = commitString + "+dirty" + copyrightYear = datetime.date.today().year + + versionInfo.commitString_ = commitString + versionInfo.copyrightYear_ = copyrightYear + versionInfo.versionString_ = args.version_ + + print("Commit String: " + str(versionInfo.commitString_)) + print("Copyright Year: " + str(versionInfo.copyrightYear_)) + print("Version String: " + str(versionInfo.versionString_)) + + return versionInfo + +def LoadCache(args): + print("Loading cache") + + cache = None + + try: + with open(args.cache_) as f: + data = json.load(f) + cache = VersionInfo() + if Keys.CommitString in data: + cache.commitString_ = data[Keys.CommitString] + if Keys.CopyrightYear in data: + cache.copyrightYear_ = data[Keys.CopyrightYear] + if Keys.VersionString in data: + cache.versionString_ = data[Keys.VersionString] + except Exception as ex: + # Ignore error if cache is not found + pass + + return cache + +def WriteHeader(versionInfo: VersionInfo, args): + print("Writing header") + + try: + pathlib.Path(args.outputHeader_).parent.mkdir(exist_ok=True, parents=True) + with open(args.inputHeader_) as fi, open(args.outputHeader_, 'w') as fo: + for line in fi: + for key in kKeys_: + line = line.replace("${" + key + "}", str(versionInfo.Value(key))) + fo.write(line) + except Exception as ex: + print("Error writing header: " + repr(ex)) + return False + + return True + +def UpdateCache(versionInfo: VersionInfo, args): + print("Updating cache") + + data = {} + data[Keys.CommitString] = versionInfo.commitString_ + data[Keys.CopyrightYear] = versionInfo.copyrightYear_ + data[Keys.VersionString] = versionInfo.versionString_ + + try: + pathlib.Path(args.cache_).parent.mkdir(exist_ok=True, parents=True) + with open(args.cache_, 'w') as f: + json.dump(data, f, indent=4) + except Exception as ex: + print("Error updating cache: " + repr(ex)) + +args = ParseArguments() +versionInfo = CollectVersionInfo(args) +cache = LoadCache(args) + +if versionInfo == cache: + print("No version changes detected") +else: + if WriteHeader(versionInfo, args): + UpdateCache(versionInfo, args) diff --git a/tools/setup-common.bat b/tools/setup-common.bat index 8e1304a4..09ad52ff 100644 --- a/tools/setup-common.bat +++ b/tools/setup-common.bat @@ -1,5 +1,6 @@ pip install conan pip install geopandas +pip install GitPython pip install sphinx pip install sphinx_rtd_theme pip install breathe