46 "each \033[1mpath\033[22m is either a repository or contains repositories as subdirectories.\n" |
47 "each \033[1mpath\033[22m is either a repository or contains repositories as subdirectories.\n" |
47 "You can change the \033[1mdepth\033[22m to support other directory structures.\n\n" |
48 "You can change the \033[1mdepth\033[22m to support other directory structures.\n\n" |
48 "When you do not specify \033[1m--no-pull\033[22m, this tool will execute the pull command\n" |
49 "When you do not specify \033[1m--no-pull\033[22m, this tool will execute the pull command\n" |
49 "(and for hg the update command) before retrieving the commit log, assuming\n" |
50 "(and for hg the update command) before retrieving the commit log, assuming\n" |
50 "to be on the default branch with \033[4mno uncommitted changes\033[24m.\n\n" |
51 "to be on the default branch with \033[4mno uncommitted changes\033[24m.\n\n" |
51 "The default output format prints an HTML page to stdout. In all cases, a\n" |
52 "Afterwards, this tool prints an HTML page to stdout. A separate heap map is\n" |
52 "separate heat map is generated for each author, but all repositories are,\n" |
53 "generated for each author showing commits across all repositories, unless the\n" |
53 "accumulated unless the \033[1m--separate\033[22m option is specified.\n" |
54 "\033[1m--separate\033[22m option is specified in which case each repository is displayed with\n" |
|
55 "its own heat map.\n" |
54 , stderr); |
56 , stderr); |
55 } |
57 } |
56 |
58 |
57 static bool chk_arg(const char* arg, const char* opt1, const char* opt2) { |
59 static bool chk_arg(const char *arg, const char *opt1, const char *opt2) { |
58 return strcmp(arg, opt1) == 0 || (opt2 != nullptr && strcmp(arg, opt2) == 0); |
60 return strcmp(arg, opt1) == 0 || (opt2 != nullptr && strcmp(arg, opt2) == 0); |
59 } |
61 } |
60 |
62 |
61 template<typename T> |
63 template<typename T> |
62 static bool parse_unsigned(const char *str, T *result, unsigned long max) { |
64 static bool parse_unsigned(const char *str, T *result, unsigned long max) { |
86 if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.year, 9999)) { |
88 if (i + 1 >= argc || parse_unsigned(argv[++i], &settings.year, 9999)) { |
87 fputs("missing or invalid year\n", stderr); |
89 fputs("missing or invalid year\n", stderr); |
88 return -1; |
90 return -1; |
89 } |
91 } |
90 } else if (chk_arg(argv[i], "-n", "--no-pull")) { |
92 } else if (chk_arg(argv[i], "-n", "--no-pull")) { |
91 settings.nopull = true; |
93 settings.update_repos = false; |
92 } else if (chk_arg(argv[i], "-s", "--separate")) { |
94 } else if (chk_arg(argv[i], "-s", "--separate")) { |
93 settings.separate = true; |
95 settings.separate = true; |
94 } else if (chk_arg(argv[i], "--hg", nullptr)) { |
96 } else if (chk_arg(argv[i], "--hg", nullptr)) { |
95 if (i + 1 < argc) { |
97 if (i + 1 < argc) { |
96 settings.hg.assign(argv[++i]); |
98 settings.hg.assign(argv[++i]); |
118 } |
120 } |
119 |
121 |
120 return 0; |
122 return 0; |
121 } |
123 } |
122 |
124 |
|
125 static void print_html_header() { |
|
126 puts("<html>\n\t<body>"); |
|
127 } |
|
128 |
|
129 static void print_html_footer() { |
|
130 puts("\t</body>\n</html>"); |
|
131 } |
|
132 |
123 int main(int argc, char *argv[]) { |
133 int main(int argc, char *argv[]) { |
124 fm::settings settings; |
134 fm::settings settings; |
125 |
135 |
126 if (parse_args(settings, argc, argv)) { |
136 if (parse_args(settings, argc, argv)) { |
127 return EXIT_FAILURE; |
137 return EXIT_FAILURE; |
128 } |
138 } |
129 |
139 |
|
140 fm::repositories repos; |
|
141 for (auto &&path: settings.paths) { |
|
142 repos.scan(path, settings.depth); |
|
143 } |
|
144 if (!settings.update_repos) { |
|
145 // TODO: update repositories |
|
146 } |
|
147 // TODO: calculate the heat maps |
|
148 |
|
149 print_html_header(); |
|
150 // TODO: output the heat maps here |
|
151 print_html_footer(); |
|
152 |
130 return EXIT_SUCCESS; |
153 return EXIT_SUCCESS; |
131 } |
154 } |
132 |
|