src/main.cpp

changeset 5
60c2588b4455
parent 4
82680ce258d6
child 6
1040ba37d4c9
equal deleted inserted replaced
4:82680ce258d6 5:60c2588b4455
23 */ 23 */
24 24
25 #include "settings.h" 25 #include "settings.h"
26 #include "repositories.h" 26 #include "repositories.h"
27 #include "process.h" 27 #include "process.h"
28 28 #include "heatmap.h"
29 #include "html.h"
30
31 #include <chrono>
29 #include <cstdlib> 32 #include <cstdlib>
30 #include <cstdio> 33 #include <cstdio>
31 #include <cstring> 34 #include <cstring>
32 #include <cerrno> 35 #include <cerrno>
36
37 namespace chrono = std::chrono;
33 38
34 static void print_help() { 39 static void print_help() {
35 fputs( 40 fputs(
36 "Usage: fallusmeter [OPTION]... [PATH]...\n\n" 41 "Usage: fallusmeter [OPTION]... [PATH]...\n\n"
37 "Options:\n" 42 "Options:\n"
121 } 126 }
122 127
123 return 0; 128 return 0;
124 } 129 }
125 130
126 static void print_html_header() {
127 puts("<html>\n\t<body>");
128 }
129
130 static void print_html_footer() {
131 puts("\t</body>\n</html>");
132 }
133
134 int main(int argc, char *argv[]) { 131 int main(int argc, char *argv[]) {
135 // parse settings 132 // parse settings
136 fm::settings settings; 133 fm::settings settings;
137 if (parse_args(settings, argc, argv)) { 134 if (parse_args(settings, argc, argv)) {
138 return EXIT_FAILURE; 135 return EXIT_FAILURE;
174 fprintf(stderr, "Pulling repo '%s' failed!\nMaybe there is no remote or there are local changes?\n", repo.path.c_str()); 171 fprintf(stderr, "Pulling repo '%s' failed!\nMaybe there is no remote or there are local changes?\n", repo.path.c_str());
175 } 172 }
176 } 173 }
177 } 174 }
178 } 175 }
179 // TODO: calculate the heat maps 176
180 177 // determine our reporting range
181 print_html_header(); 178 int year;
182 // TODO: output the heat maps here 179 if (settings.year == fm::settings_current_year) {
183 print_html_footer(); 180 year = static_cast<int>(chrono::year_month_day{chrono::floor<chrono::days>(chrono::system_clock::now())}.year());
181 } else {
182 year = settings.year;
183 }
184 chrono::year_month_day report_begin{chrono::year{year}, chrono::month{1}, chrono::day{1}};
185 chrono::year_month_day report_end{chrono::year{year}, chrono::month{12}, chrono::day{31}};
186
187 // read the commit logs
188 fm::heatmap heatmap;
189 for (auto &&repo : repos.list()) {
190 if (settings.separate) {
191 heatmap.set_repo(repo.path);
192 }
193 proc.chdir(repo.path);
194 if (repo.type == fm::HG) {
195 proc.setbin(settings.hg);
196 if (proc.exec_log({"log",
197 "--date", std::format("{0}-01-01 to {0}-12-31", year),
198 "--template", "{author}#{date|shortdate}\n"})) {
199 fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str());
200 return EXIT_FAILURE;
201 }
202 heatmap.add(proc.output());
203 } else {
204 proc.setbin(settings.git);
205 if (proc.exec({"log",
206 "--since", std::format("{0}-01-01", year),
207 "--until", std::format("{0}-12-31", year),
208 "--format=tformat:%an <%ae>#%cs"})) {
209 fprintf(stderr, "Reading commit log for repo '%s' failed!\n", repo.path.c_str());
210 return EXIT_FAILURE;
211 }
212 heatmap.add(proc.output());
213 }
214 }
215
216 html::open();
217 for (const auto &[repo, authors] : heatmap.data()) {
218 html::h1(repo);
219 for (const auto &[author, entries] : authors) {
220 html::h2(author);
221 html::table_begin();
222
223 // initialize counters
224 unsigned column = 0, row = 0;
225
226 // initialize first day (which must be a Monday, possibly the year before)
227 chrono::sys_days day_to_check{report_begin};
228 day_to_check -= chrono::days{chrono::weekday{day_to_check}.iso_encoding() - 1};
229
230 // remember the starting point
231 auto start = day_to_check;
232
233 // now add all entries for Monday, Tuesdays, etc. always starting back in january
234 while (true) {
235 html::row_begin(row);
236
237 // check if we need to add blank cells
238 while (day_to_check < report_begin) {
239 html::cell_out_of_range();
240 day_to_check += chrono::days{7};
241 column++;
242 }
243
244 while (day_to_check <= report_end) {
245 // get the entry from the heatmap
246 auto find_result = entries.find(day_to_check);
247 if (find_result == entries.end()) {
248 html::cell(0);
249 } else {
250 html::cell(find_result->second);
251 }
252 // advance seven days and one column
253 day_to_check += chrono::days{7};
254 column++;
255 }
256 // fill remaining columns with blank cells
257 for (unsigned i = column ; i < html::columns ; i++) {
258 html::cell_out_of_range();
259 }
260
261 // terminate the row
262 html::row_end();
263
264 // if we have seen all seven weekdays, that's it
265 if (++row == 7) break;
266
267 // otherwise, advance the starting point by one day, reset, and begin a new row
268 start += chrono::days{1};
269 day_to_check = start;
270 column =0;
271 }
272
273 html::table_end();
274 }
275 }
276 html::close();
184 277
185 return EXIT_SUCCESS; 278 return EXIT_SUCCESS;
186 } 279 }

mercurial