Thu, 12 Mar 2026 12:00:50 +0100
add options to output aggregated and/or separated heatmaps to files in one go
resolves #809
| 0 | 1 | /* Copyright 2025 Mike Becker. All rights reserved. |
| 2 | * | |
| 3 | * Redistribution and use in source and binary forms, with or without | |
| 4 | * modification, are permitted provided that the following conditions are met: | |
| 5 | * | |
| 6 | * 1. Redistributions of source code must retain the above copyright | |
| 7 | * notice, this list of conditions and the following disclaimer. | |
| 8 | * | |
| 9 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 | * notice, this list of conditions and the following disclaimer in the | |
| 11 | * documentation and/or other materials provided with the distribution. | |
| 12 | * | |
| 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 19 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| 20 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 21 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 22 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 23 | */ | |
| 24 | ||
| 1 | 25 | #include "settings.h" |
| 3 | 26 | #include "repositories.h" |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
27 | #include "process.h" |
| 5 | 28 | #include "heatmap.h" |
| 29 | #include "html.h" | |
| 1 | 30 | |
| 5 | 31 | #include <chrono> |
| 1 | 32 | #include <cstdlib> |
| 33 | #include <cstdio> | |
| 34 | #include <cstring> | |
| 35 | #include <cerrno> | |
| 36 | ||
|
44
de22ded6d50a
add total commits counters
Mike Becker <universe@uap-core.de>
parents:
41
diff
changeset
|
37 | #include <numeric> |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
38 | #include <ranges> |
|
44
de22ded6d50a
add total commits counters
Mike Becker <universe@uap-core.de>
parents:
41
diff
changeset
|
39 | |
| 13 | 40 | using namespace std::chrono; |
| 5 | 41 | |
|
73
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
42 | static constexpr auto program_version = "1.2.0-preview"; |
| 29 | 43 | |
| 1 | 44 | static void print_help() { |
| 45 | fputs( | |
|
23
b4979c194dc8
replace working title with official project title
Mike Becker <universe@uap-core.de>
parents:
21
diff
changeset
|
46 | "Usage: repoheat [OPTION]... [PATH]...\n\n" |
| 1 | 47 | "Options:\n" |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
48 | " -a, --author <name> Only report this author\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
49 | " (repeat option to report multiple authors)\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
50 | " -A, --authormap <file> Apply an author mapping file\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
51 | " --csv Output the gathered data as CSV to stdout\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
52 | " --csv-output <file> Write CSV data to file instead of stdout\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
53 | " -d, --depth <num> The search depth (default: 1, max: 255)\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
54 | " -f, --fragment [indent] Output as fragment (HTML only)\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
55 | " -h, --help Print this help message\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
56 | " -o, --output <file> Write output to file instead of stdout\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
57 | " -p, --pull Try to pull the repositories\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
58 | " -s, --separate Output a separate heat map for each repository\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
59 | " -S, --separate-output <file> Write results for -s to file instead of stdout\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
60 | " --styles-and-script Output the default CSS and Javascript and quit\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
61 | " -V, --version Output the version of this program and exit\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
62 | " -y, --year <year> The year for which to create the heat map\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
63 | " --hg <path> Path to hg binary (default: /usr/bin/hg)\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
64 | " --git <path> Path to git binary (default: /usr/bin/git)\n\n" |
| 1 | 65 | "Scans all specified paths recursively for Mercurial and Git repositories and\n" |
| 66 | "creates a commit heat map for the specified \033[1myear\033[22m or the current year.\n" | |
| 67 | "By default, the recursion \033[1mdepth\033[22m is one, meaning that this tool assumes that\n" | |
| 68 | "each \033[1mpath\033[22m is either a repository or contains repositories as subdirectories.\n" | |
| 69 | "You can change the \033[1mdepth\033[22m to support other directory structures.\n\n" | |
|
27
d2eee642a31b
do not pull repos by default - fixes #587
Mike Becker <universe@uap-core.de>
parents:
24
diff
changeset
|
70 | "When you specify the \033[1m--pull\033[22m option, this tool will execute the pull command\n" |
| 1 | 71 | "(and for hg the update command) before retrieving the commit log, assuming\n" |
|
9
98312f94dbdd
skip authorization requests when pulling
Mike Becker <universe@uap-core.de>
parents:
8
diff
changeset
|
72 | "to be on the default branch with \033[4mno uncommitted changes\033[24m. If pulling leads to\n" |
|
98312f94dbdd
skip authorization requests when pulling
Mike Becker <universe@uap-core.de>
parents:
8
diff
changeset
|
73 | "an error, an error message is written to stderr and the process continues\n" |
|
98312f94dbdd
skip authorization requests when pulling
Mike Becker <universe@uap-core.de>
parents:
8
diff
changeset
|
74 | "with the repository in its current state. This is also the case when pulling\n" |
|
27
d2eee642a31b
do not pull repos by default - fixes #587
Mike Becker <universe@uap-core.de>
parents:
24
diff
changeset
|
75 | "would require authorization.\n\n" |
| 14 | 76 | "By default, this tool reports commits from all authors. If you want to include\n" |
| 77 | "only specific authors in the report, you can use the \033[1m--author\033[22m option with as\n" | |
| 78 | "many authors as you like. You can specify either the full author strings with\n" | |
| 79 | "name and mail address, just the mail address, or even just the local-part of\n" | |
| 80 | "the mail address. In case your repository contains commits from an author who\n" | |
| 81 | "used different names or mail addresses, you can use the \033[1m--authormap\033[22m option\n" | |
| 82 | "to specify a file that contains pairs of author strings, like in the following\n" | |
| 83 | "example:\n\n" | |
| 84 | " Full Name <full.name@example.org> = New Name <new.name@example.org>\n" | |
| 16 | 85 | " just.mail@example.org = Jus Mail <just.mail@example.org>\n" |
| 86 | " jane = Jane Doe <jane.doe@example.org>\n\n" | |
| 14 | 87 | "The different variants of full string, only mail address, and only local-part\n" |
| 16 | 88 | "should \033[4monly\033[24m be used on the left-hand side. When you use the \033[1m--author\033[22m option at\n" |
| 89 | "the same time, you only need to specify the new author names.\n\n" | |
| 14 | 90 | "Finally, this tool prints an HTML page to stdout. A separate heap map is\n" |
| 3 | 91 | "generated for each author showing commits across all repositories, unless the\n" |
| 92 | "\033[1m--separate\033[22m option is specified in which case each repository is displayed with\n" | |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
93 | "its own heat map.\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
94 | "If you use \033[1m--separate-output\033[22m you can specify a file instead, and both the\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
95 | "aggregated and separated heat maps are written. The aggregated output is still\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
96 | "written to stdout unless you specify a file with \033[1m--output\033[22m.\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
97 | "By using the \033[1m--fragment\033[22m option, the tool only outputs a single HTML div\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
98 | "container without any header or footer that can be embedded in your custom web\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
99 | "page. You can optionally specify an indentation for that container (default is\n" |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
100 | "0 and maximum is 12).\n" |
|
73
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
101 | "When you want to combine this with the default style and scripts, you can use\n" |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
102 | "the \033[1m--styles-and-script\033[22m option print the defaults to stdout and redirect them\n" |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
103 | "into a file when you are composing your custom HTML page.\n\n" |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
104 | "In case you want to work with the raw data, you can advise the tool to output\n" |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
105 | "the data in CSV format with the \033[1m--csv\033[22m option. The CSV data will be written to\n" |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
106 | "stdout instead of the HTML. You can use \033[1m--csv-output\033[22m to specify a file, instead.\n" |
| 1 | 107 | , stderr); |
| 108 | } | |
| 109 | ||
| 3 | 110 | static bool chk_arg(const char *arg, const char *opt1, const char *opt2) { |
| 1 | 111 | return strcmp(arg, opt1) == 0 || (opt2 != nullptr && strcmp(arg, opt2) == 0); |
| 112 | } | |
| 113 | ||
| 114 | template<typename T> | |
| 115 | static bool parse_unsigned(const char *str, T *result, unsigned long max) { | |
| 116 | char *endptr; | |
| 117 | errno = 0; | |
| 118 | unsigned long d = strtoul(str, &endptr, 10); | |
| 119 | if (*endptr != '\0' || errno == ERANGE) return true; | |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
120 | if (d <= max) { |
| 1 | 121 | *result = d; |
| 122 | return false; | |
| 123 | } else { | |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
124 | errno = ERANGE; |
| 1 | 125 | return true; |
| 126 | } | |
| 127 | } | |
| 128 | ||
| 129 | static int parse_args(fm::settings &settings, int argc, char *argv[]) { | |
| 130 | for (int i = 1; i < argc; i++) { | |
| 131 | if (chk_arg(argv[i], "-h", "--help")) { | |
| 132 | print_help(); | |
| 29 | 133 | return 1; |
| 1 | 134 | } else if (chk_arg(argv[i], "-d", "--depth")) { |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
135 | if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.depth, 255)) { |
| 1 | 136 | fputs("missing or invalid depth\n", stderr); |
| 137 | return -1; | |
| 138 | } | |
| 139 | } else if (chk_arg(argv[i], "-y", "--year")) { | |
| 140 | if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.year, 9999)) { | |
| 141 | fputs("missing or invalid year\n", stderr); | |
| 142 | return -1; | |
| 143 | } | |
| 14 | 144 | } else if (chk_arg(argv[i], "-a", "--author")) { |
| 145 | if (i + 1 < argc) { | |
| 146 | settings.authors.emplace_back(argv[++i]); | |
| 147 | } else { | |
| 148 | fputs("missing author name\n", stderr); | |
| 149 | return -1; | |
| 150 | } | |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
151 | } else if (chk_arg(argv[i], "--csv", nullptr)) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
152 | settings.csv = true; |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
153 | } else if (chk_arg(argv[i], "--csv-output", nullptr)) { |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
154 | if (i + 1 < argc) { |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
155 | settings.csv = true; |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
156 | settings.csv_path.assign(argv[++i]); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
157 | } else { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
158 | fputs("missing csv path\n", stderr); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
159 | return -1; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
160 | } |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
161 | } else if (chk_arg(argv[i], "-o", "--output")) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
162 | if (i + 1 < argc) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
163 | settings.out_path.assign(argv[++i]); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
164 | } else { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
165 | fputs("missing output path\n", stderr); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
166 | return -1; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
167 | } |
|
27
d2eee642a31b
do not pull repos by default - fixes #587
Mike Becker <universe@uap-core.de>
parents:
24
diff
changeset
|
168 | } else if (chk_arg(argv[i], "-p", "--pull")) { |
|
d2eee642a31b
do not pull repos by default - fixes #587
Mike Becker <universe@uap-core.de>
parents:
24
diff
changeset
|
169 | settings.update_repos = true; |
|
20
8639ccd855ba
implement --fragment option
Mike Becker <universe@uap-core.de>
parents:
19
diff
changeset
|
170 | } else if (chk_arg(argv[i], "-f", "--fragment")) { |
|
8639ccd855ba
implement --fragment option
Mike Becker <universe@uap-core.de>
parents:
19
diff
changeset
|
171 | settings.fragment = true; |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
172 | if (i + 1 < argc && !parse_unsigned(argv[i+1], &settings.fragment_indent, html::max_external_indentation)) { |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
173 | i++; |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
174 | } else if (errno == ERANGE) { |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
175 | fputs("invalid fragment indentation\n", stderr); |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
176 | return -1; |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
177 | } |
| 1 | 178 | } else if (chk_arg(argv[i], "-s", "--separate")) { |
| 179 | settings.separate = true; | |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
180 | } else if (chk_arg(argv[i], "-S", "--separate-output")) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
181 | if (i + 1 < argc) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
182 | settings.separate = true; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
183 | settings.separate_path.assign(argv[++i]); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
184 | } else { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
185 | fputs("missing separate output path\n", stderr); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
186 | return -1; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
187 | } |
| 16 | 188 | } else if (chk_arg(argv[i], "-A", "--authormap")) { |
| 189 | if (i + 1 < argc) { | |
| 190 | if (settings.parse_authormap(argv[++i])) { | |
| 191 | fputs("parsing authormap failed\n", stderr); | |
| 192 | return -1; | |
| 193 | } | |
| 194 | } else { | |
| 195 | fputs("missing filename for authormap\n", stderr); | |
| 196 | return -1; | |
| 197 | } | |
| 29 | 198 | } else if (chk_arg(argv[i], "-V", "--version")) { |
| 199 | printf("repoheat version %s\n", program_version); | |
| 200 | return 1; | |
| 1 | 201 | } else if (chk_arg(argv[i], "--hg", nullptr)) { |
| 202 | if (i + 1 < argc) { | |
| 203 | settings.hg.assign(argv[++i]); | |
| 204 | } else { | |
| 205 | fputs("--hg is expecting a path\n", stderr); | |
| 206 | return -1; | |
| 207 | } | |
| 208 | } else if (chk_arg(argv[i], "--git", nullptr)) { | |
| 209 | if (i + 1 < argc) { | |
| 210 | settings.git.assign(argv[++i]); | |
| 211 | } else { | |
| 212 | fputs("--git is expecting a path\n", stderr); | |
| 213 | return -1; | |
| 214 | } | |
|
73
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
215 | } else if (chk_arg(argv[i], "--styles-and-script", nullptr)) { |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
216 | settings.styles_and_script = true; |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
217 | if (argc != 2) { |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
218 | fputs("Error: --styles-and-script must be the only option when present\n", stderr); |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
219 | return -1; |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
220 | } |
| 1 | 221 | } else if (argv[i][0] == '-') { |
| 222 | fprintf(stderr, "Unknown option: %s\n", argv[i]); | |
| 223 | return -1; | |
| 224 | } else { | |
| 225 | settings.paths.emplace_back(argv[i]); | |
| 226 | } | |
| 227 | } | |
| 228 | ||
| 229 | if (settings.paths.empty()) { | |
| 230 | settings.paths.emplace_back("./"); | |
| 231 | } | |
| 232 | ||
| 0 | 233 | return 0; |
| 234 | } | |
| 235 | ||
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
236 | static void generate_html( |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
237 | const fm::settings &settings, |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
238 | year report_year, year_month_day report_begin, year_month_day report_end, |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
239 | const fm::heatmap &heatmap) { |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
240 | const auto &heatmap_data = settings.separate ? heatmap.separated() : heatmap.aggregated(); |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
241 | html::open(settings.fragment, settings.fragment_indent); |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
242 | for (const auto &[repo, authors] : heatmap_data) { |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
243 | bool h1_rendered = false; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
244 | for (const auto &[author, entries] : authors) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
245 | if (settings.exclude_author(author)) continue; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
246 | if (!h1_rendered) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
247 | html::heading_repo(repo); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
248 | h1_rendered = true; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
249 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
250 | html::chart_begin(repo, author); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
251 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
252 | const auto commits_per_month = heatmap.commits_per_month(repo, author, report_year); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
253 | const auto total_commits = std::accumulate(commits_per_month.begin(), commits_per_month.end(), 0u, |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
254 | [](unsigned sum, const auto &summary) { return sum + summary.count(); }); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
255 | html::heading_author(author, total_commits); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
256 | html::table_begin(report_year, settings.separate, commits_per_month); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
257 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
258 | // initialize counters |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
259 | unsigned column = 0, row = 0; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
260 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
261 | // initialize the first day (which must be a Monday, possibly the year before) |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
262 | sys_days day_to_check = January / Monday[1] / report_year; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
263 | if (year_month_day{day_to_check}.day() != 1d) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
264 | day_to_check -= days{7}; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
265 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
266 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
267 | // remember the starting point |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
268 | auto start = day_to_check; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
269 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
270 | // now add all entries for Monday, Tuesdays, etc. always starting back in January |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
271 | while (true) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
272 | html::row_begin(row); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
273 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
274 | // check if we need to add blank cells |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
275 | while (day_to_check < report_begin) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
276 | html::cell_out_of_range(); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
277 | day_to_check += days{7}; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
278 | column++; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
279 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
280 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
281 | while (day_to_check <= report_end) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
282 | // get the entry from the heatmap |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
283 | auto find_result = entries.find(day_to_check); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
284 | if (find_result == entries.end()) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
285 | html::cell(day_to_check); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
286 | } else { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
287 | html::cell(day_to_check, settings.separate, find_result->second); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
288 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
289 | // advance seven days and one column |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
290 | day_to_check += days{7}; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
291 | column++; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
292 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
293 | // fill remaining columns with blank cells |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
294 | for (unsigned i = column ; i < html::columns ; i++) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
295 | html::cell_out_of_range(); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
296 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
297 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
298 | // terminate the row |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
299 | html::row_end(); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
300 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
301 | // if we have seen all seven weekdays, that's it |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
302 | if (++row == 7) break; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
303 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
304 | // otherwise, advance the starting point by one day, reset, and begin a new row |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
305 | start += days{1}; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
306 | day_to_check = start; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
307 | column =0; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
308 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
309 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
310 | html::table_end(); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
311 | html::chart_end(); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
312 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
313 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
314 | html::close(settings.fragment); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
315 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
316 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
317 | static int generate_csv(const fm::settings &settings, const fm::heatmap &heatmap) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
318 | FILE *out; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
319 | if (settings.csv_path.empty()) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
320 | out = stdout; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
321 | } else { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
322 | out = fopen(settings.csv_path.c_str(), "w"); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
323 | if (out == nullptr) return 1; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
324 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
325 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
326 | auto escape_csv = [](const std::string &str) -> std::string { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
327 | std::string result; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
328 | result.reserve(str.size()+2); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
329 | result += '"'; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
330 | for (char c : str) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
331 | if (c == '"') { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
332 | result += '"'; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
333 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
334 | result += c; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
335 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
336 | result += '"'; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
337 | return result; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
338 | }; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
339 | |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
340 | fprintf(out, "repository,author,date,hash,summary,is_tag\n"); |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
341 | for (const auto &authors: heatmap.aggregated() | std::views::values) { |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
342 | for (const auto &[author, entries]: authors) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
343 | for (const auto &[date, commits]: entries) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
344 | for (const auto &[repo, infos] : commits.summaries) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
345 | for (const auto &info : infos) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
346 | fprintf(out, "%s,%s,%d-%02u-%02u,%s,%s,false\n", |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
347 | repo.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
348 | author.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
349 | static_cast<int>(date.year()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
350 | static_cast<unsigned>(date.month()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
351 | static_cast<unsigned>(date.day()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
352 | info.hash.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
353 | escape_csv(info.message).c_str() |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
354 | ); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
355 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
356 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
357 | for (const auto &[repo, infos] : commits.tags) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
358 | for (const auto &info : infos) { |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
359 | fprintf(out, "%s,%s,%d-%02u-%02u,%s,%s,true\n", |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
360 | repo.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
361 | author.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
362 | static_cast<int>(date.year()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
363 | static_cast<unsigned>(date.month()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
364 | static_cast<unsigned>(date.day()), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
365 | info.hash.c_str(), |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
366 | escape_csv(info.message).c_str() |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
367 | ); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
368 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
369 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
370 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
371 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
372 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
373 | fclose(out); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
374 | return 0; |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
375 | } |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
376 | |
| 1 | 377 | int main(int argc, char *argv[]) { |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
378 | // parse settings |
| 1 | 379 | fm::settings settings; |
| 29 | 380 | if (int result = parse_args(settings, argc, argv); result != 0) { |
| 381 | return result < 0 ? EXIT_FAILURE : EXIT_SUCCESS; | |
| 1 | 382 | } |
| 383 | ||
|
73
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
384 | // check special options |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
385 | if (settings.styles_and_script) { |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
386 | // note: no need to set output path - not supported for styles and scripts |
|
73
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
387 | html::styles_and_script(); |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
388 | return 0; |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
389 | } |
|
707f42bb0484
add --styles-and-script option to output default CSS and Javascript for page composition
Mike Becker <universe@uap-core.de>
parents:
71
diff
changeset
|
390 | |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
391 | // check hg and git |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
392 | fm::process proc; |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
393 | proc.setbin(settings.hg); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
394 | if (proc.exec({"--version"})) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
395 | fprintf(stderr, "Testing hg binary '%s' failed!\n", settings.hg.c_str()); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
396 | return EXIT_FAILURE; |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
397 | } |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
398 | proc.setbin(settings.git); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
399 | if (proc.exec({"--version"})) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
400 | fprintf(stderr, "Testing git binary '%s' failed!\n", settings.git.c_str()); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
401 | return EXIT_FAILURE; |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
402 | } |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
403 | |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
404 | // scan for repos |
| 3 | 405 | fm::repositories repos; |
| 406 | for (auto &&path: settings.paths) { | |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
407 | if (!fm::repositories::exists(path)) { |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
408 | fprintf(stderr, "Path '%s' does not exist!\n", path.c_str()); |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
409 | return EXIT_FAILURE; |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
410 | } |
| 3 | 411 | repos.scan(path, settings.depth); |
| 412 | } | |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
413 | |
|
52
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
414 | // check if we found something |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
415 | if (repos.count() == 0) { |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
416 | fprintf(stderr, "No repositories found!\n"); |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
417 | return EXIT_FAILURE; |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
418 | } |
|
e9edc3bd0301
add custom fragment indentation
Mike Becker <universe@uap-core.de>
parents:
46
diff
changeset
|
419 | |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
420 | // update repos, if not disabled |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
421 | if (settings.update_repos) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
422 | for (auto &&repo : repos.list()) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
423 | proc.chdir(repo.path); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
424 | if (repo.type == fm::HG) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
425 | proc.setbin(settings.hg); |
|
9
98312f94dbdd
skip authorization requests when pulling
Mike Becker <universe@uap-core.de>
parents:
8
diff
changeset
|
426 | if (proc.exec({"pull", "-y"})) { |
|
21
bc8b76ca9ee9
fix possible misleading error output
Mike Becker <universe@uap-core.de>
parents:
20
diff
changeset
|
427 | fprintf(stderr, "Pulling repo '%s' failed - continue without pull.\n", repo.path.c_str()); |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
428 | } else if (proc.exec({"update"})) { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
429 | fprintf(stderr, "Updating repo '%s' failed!\nMaybe there are local changes?\n", repo.path.c_str()); |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
430 | } |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
431 | } else { |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
432 | proc.setbin(settings.git); |
|
67
7962d771b939
fix that only the main branch was considered in git repositories
Mike Becker <universe@uap-core.de>
parents:
65
diff
changeset
|
433 | if (proc.exec({"pull", "-q", "--all"})) { |
|
21
bc8b76ca9ee9
fix possible misleading error output
Mike Becker <universe@uap-core.de>
parents:
20
diff
changeset
|
434 | fprintf(stderr, "Pulling repo '%s' failed - continue without pull.\n", repo.path.c_str()); |
|
4
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
435 | } |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
436 | } |
|
82680ce258d6
add automatic pull/udate of repositories
Mike Becker <universe@uap-core.de>
parents:
3
diff
changeset
|
437 | } |
| 3 | 438 | } |
| 5 | 439 | |
| 440 | // determine our reporting range | |
| 13 | 441 | year report_year{ |
| 442 | settings.year == fm::settings_current_year | |
| 443 | ? year_month_day{floor<days>(system_clock::now())}.year() | |
| 444 | : year{settings.year} | |
| 445 | }; | |
| 446 | year_month_day report_begin{report_year, January, 1d}; | |
| 447 | year_month_day report_end{report_year, December, 31d}; | |
| 5 | 448 | |
| 449 | // read the commit logs | |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
450 | fm::heatmap heatmap; |
| 5 | 451 | for (auto &&repo : repos.list()) { |
|
56
3d2720f95cfb
fix that commits were not listed per repository in the combined view
Mike Becker <universe@uap-core.de>
parents:
54
diff
changeset
|
452 | heatmap.set_repo(repo.name); |
| 5 | 453 | proc.chdir(repo.path); |
| 454 | if (repo.type == fm::HG) { | |
| 455 | proc.setbin(settings.hg); | |
| 456 | if (proc.exec_log({"log", | |
| 36 | 457 | "--date", std::format("{0}-01-01 00:00:00 to {0}-12-31 23:59:59", report_year), |
|
76
110a234a3260
add reading commit hashes from the commit log - resolves #807
Mike Becker <universe@uap-core.de>
parents:
75
diff
changeset
|
458 | "--template", "{node}#{author}#{date|shortdate}#{tags}#{desc|firstline}\\n"})) { |
| 5 | 459 | fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str()); |
| 460 | return EXIT_FAILURE; | |
| 461 | } | |
| 16 | 462 | heatmap.add(settings, proc.output()); |
| 5 | 463 | } else { |
| 464 | proc.setbin(settings.git); | |
|
8
6a2e20a4a8ff
fix log not being captured from git
Mike Becker <universe@uap-core.de>
parents:
7
diff
changeset
|
465 | if (proc.exec_log({"log", |
|
67
7962d771b939
fix that only the main branch was considered in git repositories
Mike Becker <universe@uap-core.de>
parents:
65
diff
changeset
|
466 | "--all", |
|
61
d77763d2fdda
highlight days with tags - resolves #672
Mike Becker <universe@uap-core.de>
parents:
59
diff
changeset
|
467 | "--decorate=short", |
|
d77763d2fdda
highlight days with tags - resolves #672
Mike Becker <universe@uap-core.de>
parents:
59
diff
changeset
|
468 | "--decorate-refs=refs/tags/", |
| 36 | 469 | "--since", std::format("{0}-01-01 00:00:00", report_year), |
| 470 | "--until", std::format("{0}-12-31 23:59:59", report_year), | |
|
76
110a234a3260
add reading commit hashes from the commit log - resolves #807
Mike Becker <universe@uap-core.de>
parents:
75
diff
changeset
|
471 | "--format=tformat:%H#%an <%ae>#%cs#%(decorate:prefix=,suffix=,tag=,separator= )#%s"})) { |
| 5 | 472 | fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str()); |
| 473 | return EXIT_FAILURE; | |
| 474 | } | |
| 16 | 475 | heatmap.add(settings, proc.output()); |
| 5 | 476 | } |
| 477 | } | |
| 478 | ||
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
479 | const bool write_csv = settings.csv; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
480 | const bool write_separate = settings.separate; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
481 | const bool write_default = !settings.out_path.empty() || ( |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
482 | !(write_csv && settings.csv_path.empty()) |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
483 | && !(write_separate && settings.separate_path.empty()) |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
484 | ); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
485 | |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
486 | if (write_csv) { |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
487 | if (generate_csv(settings, heatmap)) { |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
488 | perror("Cannot open file for writing"); |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
489 | return EXIT_FAILURE; |
| 5 | 490 | } |
| 491 | } | |
|
81
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
492 | if (write_separate) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
493 | settings.separate = true; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
494 | if (html::set_output(settings.separate_path)) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
495 | perror("Cannot open file for writing"); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
496 | return EXIT_FAILURE; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
497 | } |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
498 | generate_html(settings, report_year, report_begin, report_end, heatmap); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
499 | } |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
500 | if (write_default) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
501 | settings.separate = false; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
502 | if (html::set_output(settings.out_path)) { |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
503 | perror("Cannot open file for writing"); |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
504 | return EXIT_FAILURE; |
|
1ff88eb9555c
add options to output aggregated and/or separated heatmaps to files in one go
Mike Becker <universe@uap-core.de>
parents:
79
diff
changeset
|
505 | } |
|
78
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
506 | generate_html(settings, report_year, report_begin, report_end, heatmap); |
|
5177d8af5536
add CSV export of raw data - resolves #806
Mike Becker <universe@uap-core.de>
parents:
76
diff
changeset
|
507 | } |
| 3 | 508 | |
| 1 | 509 | return EXIT_SUCCESS; |
| 510 | } |