implement author filter

Sat, 01 Feb 2025 15:06:48 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 01 Feb 2025 15:06:48 +0100
changeset 14
f0ae064c5b9c
parent 13
e714005f3e9d
child 15
ef0f2497843e

implement author filter

src/Makefile file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/settings.cpp file | annotate | diff | comparison | revisions
src/settings.h file | annotate | diff | comparison | revisions
--- a/src/Makefile	Sat Feb 01 14:19:36 2025 +0100
+++ b/src/Makefile	Sat Feb 01 15:06:48 2025 +0100
@@ -23,7 +23,7 @@
 
 include ../config.mk
 
-SRC=main.cpp process.cpp repositories.cpp heatmap.cpp html.cpp
+SRC=main.cpp settings.cpp process.cpp repositories.cpp heatmap.cpp html.cpp
 OBJ=$(SRC:%.cpp=../build/%.o)
 OUTPUT=../build/fallusmeter
 
@@ -48,7 +48,8 @@
 	@echo "Compiling $<"
 	$(CXX) -o $@ $(CXXFLAGS)  -c $<
 
-../build/main.o: main.cpp settings.h repositories.h process.h heatmap.h
+../build/main.o: main.cpp settings.h repositories.h process.h heatmap.h \
+ html.h
 	@echo "Compiling $<"
 	$(CXX) -o $@ $(CXXFLAGS)  -c $<
 
@@ -60,3 +61,7 @@
 	@echo "Compiling $<"
 	$(CXX) -o $@ $(CXXFLAGS)  -c $<
 
+../build/settings.o: settings.cpp
+	@echo "Compiling $<"
+	$(CXX) -o $@ $(CXXFLAGS)  -c $<
+
--- a/src/main.cpp	Sat Feb 01 14:19:36 2025 +0100
+++ b/src/main.cpp	Sat Feb 01 15:06:48 2025 +0100
@@ -40,13 +40,16 @@
     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"
+        "   -a, --author <name>       Only report this author\n"
+        "                             (repeat option to report multiple authors)\n"
+        "   -A, --authormap <file>    Apply an author mapping file\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"
@@ -58,7 +61,21 @@
         "an error, an error message is written to stderr and the process continues\n"
         "with the repository in its current state. This is also the case when pulling\n"
         "requires authorization.\n\n"
-        "Afterwards, this tool prints an HTML page to stdout. A separate heap map is\n"
+        "By default, this tool reports commits from all authors. If you want to include\n"
+        "only specific authors in the report, you can use the \033[1m--author\033[22m option with as\n"
+        "many authors as you like. You can specify either the full author strings with\n"
+        "name and mail address, just the mail address, or even just the local-part of\n"
+        "the mail address. In case your repository contains commits from an author who\n"
+        "used different names or mail addresses, you can use the \033[1m--authormap\033[22m option\n"
+        "to specify a file that contains pairs of author strings, like in the following\n"
+        "example:\n\n"
+        "   Full Name <full.name@example.org> = New Name <new.name@example.org>\n"
+        "   just.mail@example.org = new.name@example.org\n"
+        "   username = new.name\n\n"
+        "The different variants of full string, only mail address, and only local-part\n"
+        "can be combined as you like. When you use the \033[1m--author\033[22m option at the same\n"
+        "time, you only need to specify the new author names.\n\n"
+        "Finally, this tool prints an HTML page to stdout. A separate heap map is\n"
         "generated for each author showing commits across all repositories, unless the\n"
         "\033[1m--separate\033[22m option is specified in which case each repository is displayed with\n"
         "its own heat map.\n"
@@ -98,6 +115,13 @@
                 fputs("missing or invalid year\n", stderr);
                 return -1;
             }
+        } else if (chk_arg(argv[i], "-a", "--author")) {
+            if (i + 1 < argc) {
+                settings.authors.emplace_back(argv[++i]);
+            } else {
+                fputs("missing author name\n", stderr);
+                return -1;
+            }
         } else if (chk_arg(argv[i], "-n", "--no-pull")) {
             settings.update_repos = false;
         } else if (chk_arg(argv[i], "-s", "--separate")) {
@@ -219,6 +243,8 @@
     for (const auto &[repo, authors] : heatmap.data()) {
         html::h1(repo);
         for (const auto &[author, entries] : authors) {
+            if (settings.exclude_author(author)) continue;
+
             html::h2(author);
             html::table_begin(report_year);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/settings.cpp	Sat Feb 01 15:06:48 2025 +0100
@@ -0,0 +1,49 @@
+/* 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.
+ */
+
+#include "settings.h"
+
+#include <format>
+#include <algorithm>
+
+using namespace fm;
+
+[[nodiscard]] bool settings::exclude_author(const std::string &author) const {
+    // no allow-list means: always allowed
+    if (authors.empty()) return false;
+
+    // check all allowed authors
+    return std::ranges::all_of(authors, [&](const auto &allowed) {
+        // check for exact match
+        if (author == allowed) return false;
+
+        // check mail address matching
+        if (author.contains(std::format("<{}>", allowed))) return false;
+
+        // check local-part from mail address matching
+        if (author.contains(std::format("<{}@", allowed))) return false;
+
+        return true;
+    });
+}
--- a/src/settings.h	Sat Feb 01 14:19:36 2025 +0100
+++ b/src/settings.h	Sat Feb 01 15:06:48 2025 +0100
@@ -37,10 +37,13 @@
     std::string hg{"/usr/bin/hg"};
     std::string git{"/usr/bin/git"};
     std::vector<std::string> paths;
+    std::vector<std::string> authors;
     unsigned char depth = 1;
     bool update_repos = true;
     bool separate = false;
     unsigned short year = settings_current_year;
+
+    [[nodiscard]] bool exclude_author(const std::string &author) const;
 };
 
 }

mercurial