Sat, 01 Feb 2025 15:06:48 +0100
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; }; }