From 6ed48022ae46ce9b8a68dd07ddc85f6838acd802 Mon Sep 17 00:00:00 2001 From: deeaitch Date: Fri, 28 Aug 2026 01:30:44 -0400 Subject: [PATCH] Add Git-derived version reporting --- CMakeLists.txt | 28 +++++++++++++++++++++++++++- README.md | 13 +++++++++++++ typefactory/main.cpp | 22 +++++++++++++++++++--- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4f6f95..f6f7b58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,34 @@ cmake_minimum_required(VERSION 3.16) -project(kindle2notes LANGUAGES CXX) +project(kindle2notes VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(KINDLE2NOTES_VERSION "${PROJECT_VERSION}") +find_package(Git QUIET) +if(Git_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --long --dirty --always + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE KINDLE2NOTES_GIT_RESULT + OUTPUT_VARIABLE KINDLE2NOTES_GIT_DESCRIBE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + if(KINDLE2NOTES_GIT_RESULT EQUAL 0 AND NOT KINDLE2NOTES_GIT_DESCRIBE STREQUAL "") + if(KINDLE2NOTES_GIT_DESCRIBE MATCHES "^(.+)-0-g[0-9a-f]+$") + set(KINDLE2NOTES_VERSION "${CMAKE_MATCH_1}") + else() + set(KINDLE2NOTES_VERSION "${KINDLE2NOTES_GIT_DESCRIBE}") + endif() + endif() +endif() + +message(STATUS "kindle2notes version: ${KINDLE2NOTES_VERSION}") + function(kindle2notes_enable_warnings target) if(MSVC) target_compile_options(${target} PRIVATE /W4) @@ -29,3 +52,6 @@ add_executable(kindle2notes typefactory/typefactory.h ) kindle2notes_enable_warnings(kindle2notes) +target_compile_definitions(kindle2notes PRIVATE + KINDLE2NOTES_VERSION="${KINDLE2NOTES_VERSION}" +) diff --git a/README.md b/README.md index d173196..dc9abec 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,12 @@ The resulting executable is: build/kindle2notes ``` +When the source is built from Git, CMake obtains the version from +`git describe`. A build made exactly from a release tag reports only that tag +(for example, `1.0`). Later commits include their distance from the tag and +the abbreviated commit hash (for example, `1.0-3-gabc1234`). A modified +working tree also receives the `-dirty` suffix. + ## Usage Generate LaTeX: @@ -175,11 +181,18 @@ Short options are also available: ./build/kindle2notes -i input.txt -o notes.md -t md ``` +Show the version compiled into the executable: + +```bash +./build/kindle2notes --version +``` + | Argument | Short form | Description | | --- | --- | --- | | `--input` | `-i` | Path to the Kindle clippings file | | `--output` | `-o` | Path to the generated file | | `--type` | `-t` | Output format: `latex`, `md`, `org`, or `adoc` | +| `--version` | `-v` | Show the compiled version and exit | | `--help` | `-h` | Show usage information | If an unsupported output type is requested, the program prints the list of diff --git a/typefactory/main.cpp b/typefactory/main.cpp index 4a4cb62..6722dc6 100644 --- a/typefactory/main.cpp +++ b/typefactory/main.cpp @@ -9,6 +9,10 @@ #include "convertorg.h" #include "typefactory.h" +#ifndef KINDLE2NOTES_VERSION +#define KINDLE2NOTES_VERSION "unknown" +#endif + using ConverterFactory = TypeFactory; static constexpr std::array kSupportedTypes = { @@ -19,11 +23,13 @@ struct CliArgs { std::string input; std::string output; std::string type; + bool version = false; }; static void print_usage (const char *argv0) { std::cerr << "Usage: " << argv0 - << " --input --output --type \n"; + << " --input --output --type \n" + << " " << argv0 << " --version\n"; } static void print_supported_types() { @@ -47,12 +53,13 @@ static bool parse_args (int argc, char **argv, CliArgs &out) { {"input", required_argument, nullptr, 'i'}, {"output", required_argument, nullptr, 'o'}, {"type", required_argument, nullptr, 't'}, + {"version", no_argument, nullptr, 'v'}, {"help", no_argument, nullptr, 'h'}, {nullptr, 0, nullptr, 0 } }; int c = 0; - while ((c = ::getopt_long (argc, argv, "i:o:t:h", long_opts, nullptr)) != -1) { + while ((c = ::getopt_long (argc, argv, "i:o:t:vh", long_opts, nullptr)) != -1) { switch (c) { case 'i': out.input = optarg; @@ -63,6 +70,9 @@ static bool parse_args (int argc, char **argv, CliArgs &out) { case 't': out.type = optarg; break; + case 'v': + out.version = true; + break; case 'h': print_usage (argv[0]); return false; @@ -72,7 +82,8 @@ static bool parse_args (int argc, char **argv, CliArgs &out) { } } - if (out.input.empty() || out.output.empty() || out.type.empty()) { + if (!out.version && + (out.input.empty() || out.output.empty() || out.type.empty())) { print_usage (argv[0]); return false; } @@ -85,6 +96,11 @@ int main (int argc, char **argv) { if (!parse_args (argc, argv, args)) return 1; + if (args.version) { + std::cout << "kindle2notes " << KINDLE2NOTES_VERSION << '\n'; + return 0; + } + const ConverterFactory factory = build_converter_factory(); if (!factory.contains (args.type)) { std::cerr << "Unsupported output type: " << args.type << '\n';