src/main.cpp

changeset 5
60c2588b4455
parent 4
82680ce258d6
child 6
1040ba37d4c9
--- a/src/main.cpp	Tue Jan 21 21:01:54 2025 +0100
+++ b/src/main.cpp	Fri Jan 31 22:11:04 2025 +0100
@@ -25,12 +25,17 @@
 #include "settings.h"
 #include "repositories.h"
 #include "process.h"
+#include "heatmap.h"
+#include "html.h"
 
+#include <chrono>
 #include <cstdlib>
 #include <cstdio>
 #include <cstring>
 #include <cerrno>
 
+namespace chrono = std::chrono;
+
 static void print_help() {
     fputs(
         "Usage: fallusmeter [OPTION]... [PATH]...\n\n"
@@ -123,14 +128,6 @@
     return 0;
 }
 
-static void print_html_header() {
-    puts("<html>\n\t<body>");
-}
-
-static void print_html_footer() {
-    puts("\t</body>\n</html>");
-}
-
 int main(int argc, char *argv[]) {
     // parse settings
     fm::settings settings;
@@ -176,11 +173,107 @@
             }
         }
     }
-    // TODO: calculate the heat maps
+
+    // determine our reporting range
+    int year;
+    if (settings.year == fm::settings_current_year) {
+        year = static_cast<int>(chrono::year_month_day{chrono::floor<chrono::days>(chrono::system_clock::now())}.year());
+    } else {
+        year = settings.year;
+    }
+    chrono::year_month_day report_begin{chrono::year{year}, chrono::month{1}, chrono::day{1}};
+    chrono::year_month_day report_end{chrono::year{year}, chrono::month{12}, chrono::day{31}};
+
+    // read the commit logs
+    fm::heatmap heatmap;
+    for (auto &&repo : repos.list()) {
+        if (settings.separate) {
+            heatmap.set_repo(repo.path);
+        }
+        proc.chdir(repo.path);
+        if (repo.type == fm::HG) {
+            proc.setbin(settings.hg);
+            if (proc.exec_log({"log",
+                "--date", std::format("{0}-01-01 to {0}-12-31", year),
+                "--template", "{author}#{date|shortdate}\n"})) {
+                fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str());
+                return EXIT_FAILURE;
+            }
+            heatmap.add(proc.output());
+        } else {
+            proc.setbin(settings.git);
+            if (proc.exec({"log",
+                "--since", std::format("{0}-01-01", year),
+                "--until", std::format("{0}-12-31", year),
+                "--format=tformat:%an <%ae>#%cs"})) {
+                fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str());
+                return EXIT_FAILURE;
+            }
+            heatmap.add(proc.output());
+        }
+    }
+
+    html::open();
+    for (const auto &[repo, authors] : heatmap.data()) {
+        html::h1(repo);
+        for (const auto &[author, entries] : authors) {
+            html::h2(author);
+            html::table_begin();
+
+            // initialize counters
+            unsigned column = 0, row = 0;
 
-    print_html_header();
-    // TODO: output the heat maps here
-    print_html_footer();
+            // initialize first day (which must be a Monday, possibly the year before)
+            chrono::sys_days day_to_check{report_begin};
+            day_to_check -= chrono::days{chrono::weekday{day_to_check}.iso_encoding() - 1};
+
+            // remember the starting point
+            auto start = day_to_check;
+
+            // now add all entries for Monday, Tuesdays, etc. always starting back in january
+            while (true) {
+                html::row_begin(row);
+
+                // check if we need to add blank cells
+                while (day_to_check < report_begin) {
+                    html::cell_out_of_range();
+                    day_to_check += chrono::days{7};
+                    column++;
+                }
+
+                while (day_to_check <= report_end) {
+                    // get the entry from the heatmap
+                    auto find_result = entries.find(day_to_check);
+                    if (find_result == entries.end()) {
+                        html::cell(0);
+                    } else {
+                        html::cell(find_result->second);
+                    }
+                    // advance seven days and one column
+                    day_to_check += chrono::days{7};
+                    column++;
+                }
+                // fill remaining columns with blank cells
+                for (unsigned i = column ; i < html::columns ; i++) {
+                    html::cell_out_of_range();
+                }
+
+                // terminate the row
+                html::row_end();
+
+                // if we have seen all seven weekdays, that's it
+                if (++row == 7) break;
+
+                // otherwise, advance the starting point by one day, reset, and begin a new row
+                start += chrono::days{1};
+                day_to_check = start;
+                column =0;
+            }
+
+            html::table_end();
+        }
+    }
+    html::close();
 
     return EXIT_SUCCESS;
 }

mercurial