Tue, 21 Jan 2025 18:09:14 +0100
add settings and CLI
src/Makefile | file | annotate | diff | comparison | revisions | |
src/main.cpp | file | annotate | diff | comparison | revisions | |
src/settings.h | file | annotate | diff | comparison | revisions |
--- a/src/Makefile Sat Jan 11 13:45:38 2025 +0100 +++ b/src/Makefile Tue Jan 21 18:09:14 2025 +0100 @@ -40,7 +40,7 @@ FORCE: -../build/main.o: main.cpp +../build/main.o: main.cpp settings.h @echo "Compiling $<" $(CXX) -o $@ $(CXXFLAGS) -c $<
--- a/src/main.cpp Sat Jan 11 13:45:38 2025 +0100 +++ b/src/main.cpp Tue Jan 21 18:09:14 2025 +0100 @@ -22,7 +22,111 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -int main() { +#include "settings.h" + +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cerrno> + +static void print_help() { + fputs( + "Usage: fallusmeter [OPTION]... [PATH]...\n\n" + "Options:\n" + " -h, --help Print this help message\n" + " -d, --depth <num> The search depth (default: 1, max: 255)\n" + " -n, --no-pull Do not pull the repositories\n" + " -s, --separate Output a separate heat map for each repository\n" + " -y, --year <year> The year for which to create the heat map\n" + " --hg <path> Path to hg binary (default: /usr/bin/hg)\n" + " --git <path> Path to git binary (default: /usr/bin/git)\n\n" + "Scans all specified paths recursively for Mercurial and Git repositories and\n" + "creates a commit heat map for the specified \033[1myear\033[22m or the current year.\n" + "By default, the recursion \033[1mdepth\033[22m is one, meaning that this tool assumes that\n" + "each \033[1mpath\033[22m is either a repository or contains repositories as subdirectories.\n" + "You can change the \033[1mdepth\033[22m to support other directory structures.\n\n" + "When you do not specify \033[1m--no-pull\033[22m, this tool will execute the pull command\n" + "(and for hg the update command) before retrieving the commit log, assuming\n" + "to be on the default branch with \033[4mno uncommitted changes\033[24m.\n\n" + "The default output format prints an HTML page to stdout. In all cases, a\n" + "separate heat map is generated for each author, but all repositories are,\n" + "accumulated unless the \033[1m--separate\033[22m option is specified.\n" + , stderr); +} + +static bool chk_arg(const char* arg, const char* opt1, const char* opt2) { + return strcmp(arg, opt1) == 0 || (opt2 != nullptr && strcmp(arg, opt2) == 0); +} + +template<typename T> +static bool parse_unsigned(const char *str, T *result, unsigned long max) { + char *endptr; + errno = 0; + unsigned long d = strtoul(str, &endptr, 10); + if (*endptr != '\0' || errno == ERANGE) return true; + if (d < max) { + *result = d; + return false; + } else { + return true; + } +} + +static int parse_args(fm::settings &settings, int argc, char *argv[]) { + for (int i = 1; i < argc; i++) { + if (chk_arg(argv[i], "-h", "--help")) { + print_help(); + return -1; + } else if (chk_arg(argv[i], "-d", "--depth")) { + if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.depth, 256)) { + fputs("missing or invalid depth\n", stderr); + return -1; + } + } else if (chk_arg(argv[i], "-y", "--year")) { + if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.year, 9999)) { + fputs("missing or invalid year\n", stderr); + return -1; + } + } else if (chk_arg(argv[i], "-n", "--no-pull")) { + settings.nopull = true; + } else if (chk_arg(argv[i], "-s", "--separate")) { + settings.separate = true; + } else if (chk_arg(argv[i], "--hg", nullptr)) { + if (i + 1 < argc) { + settings.hg.assign(argv[++i]); + } else { + fputs("--hg is expecting a path\n", stderr); + return -1; + } + } else if (chk_arg(argv[i], "--git", nullptr)) { + if (i + 1 < argc) { + settings.git.assign(argv[++i]); + } else { + fputs("--git is expecting a path\n", stderr); + return -1; + } + } else if (argv[i][0] == '-') { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return -1; + } else { + settings.paths.emplace_back(argv[i]); + } + } + + if (settings.paths.empty()) { + settings.paths.emplace_back("./"); + } + return 0; } +int main(int argc, char *argv[]) { + fm::settings settings; + + if (parse_args(settings, argc, argv)) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/settings.h Tue Jan 21 18:09:14 2025 +0100 @@ -0,0 +1,48 @@ +/* Copyright 2025 Mike Becker. All rights reserved. +* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include <string> +#include <vector> + +namespace fm { + +constexpr static short SETTINGS_CURRENT_YEAR = 0; + +struct settings { + std::string hg{"/usr/bin/hg"}; + std::string git{"/usr/bin/git"}; + std::vector<std::string> paths; + unsigned char depth = 1; + bool nopull = false; + bool separate = false; + unsigned short year = SETTINGS_CURRENT_YEAR; +}; + +} + +#endif //SETTINGS_H