startgit

Static page generator for git repositories
git clone git://git.dimitrijedobrota.com/startgit.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

startgit-index.cpp (4041B)


0 #include <format>
1 #include <fstream>
2 #include <iostream>
4 #include <git2wrap/error.hpp>
5 #include <git2wrap/libgit2.hpp>
6 #include <hemplate/html.hpp>
7 #include <poafloc/error.hpp>
8 #include <poafloc/poafloc.hpp>
10 #include "arguments.hpp"
11 #include "document.hpp"
12 #include "repository.hpp"
14 namespace startgit
15 {
17 hemplate::element write_table_row(const std::filesystem::path& repo_path)
18 {
19 using namespace hemplate::html; // NOLINT
21 try {
22 const repository repo(repo_path);
24 for (const auto& branch : repo.get_branches()) {
25 if (branch.get_name() != "master") {
26 continue;
27 }
29 const auto url = repo.get_name() + "/master/log.html";
30 return tr {
31 td {aHref {url, repo.get_name()}},
32 td {repo.get_description()},
33 td {repo.get_owner()},
34 td {branch.get_commits()[0].get_time()},
35 };
36 }
38 std::cerr << std::format(
39 "Warning: {} doesn't have master branch\n", repo.get_path().string()
40 );
41 } catch (const git2wrap::error<git2wrap::error_code_t::enotfound>& err) {
42 std::cerr << std::format(
43 "Warning: {} is not a repository\n", repo_path.string()
44 );
45 }
47 return element {};
48 }
50 hemplate::element write_table()
51 {
52 using namespace hemplate::html; // NOLINT
54 return element {
55 h1 {args.title},
56 p {args.description},
57 table {
58 thead {
59 tr {
60 td {"Name"},
61 td {"Description"},
62 td {"Owner"},
63 td {"Last commit"},
64 },
65 },
66 tbody {
67 transform(args.repos, write_table_row),
68 },
69 }
70 };
71 }
73 } // namespace startgit
75 int main(int argc, const char* argv[])
76 {
77 using namespace hemplate::html; // NOLINT
78 using namespace startgit; // NOLINT
79 using namespace poafloc; // NOLINT
81 auto program = parser<arguments_t> {
82 positional {
83 argument_list {
84 "repositories",
85 &arguments_t::set_repository,
86 },
87 },
88 group {
89 "Output mode",
90 direct {
91 "o output",
92 &arguments_t::output_dir,
93 "DIR Output directory",
94 },
95 boolean {
96 "f force",
97 &arguments_t::force,
98 "Force write even if file exists",
99 },
100 },
101 group {
102 "General Information",
103 direct {
104 "b base",
105 &arguments_t::set_base,
106 "URL Absolute destination",
107 },
108 direct {
109 "r resources",
110 &arguments_t::set_resource,
111 "URL Location of styles and scripts",
112 },
113 direct {
114 "a author",
115 &arguments_t::author,
116 "NAME Owner of the repository",
117 },
118 direct {
119 "t title",
120 &arguments_t::title,
121 "TITLE Title for the index page",
122 },
123 direct {
124 "d description",
125 &arguments_t::description,
126 "DESC Description for the index page",
127 },
128 },
129 };
131 try {
132 program(args, argc, argv);
133 if (args.repos.empty()) {
134 return -1;
137 const git2wrap::libgit2 libgit;
139 auto& output_dir = args.output_dir;
140 std::filesystem::create_directories(output_dir);
141 output_dir = std::filesystem::canonical(output_dir);
143 std::ofstream ofs(args.output_dir / "index.html");
144 const document doc {
145 args.title, args.description, args.author, "./", /* has_feed = */ false
146 };
147 doc.render(ofs, write_table);
148 } catch (const poafloc::runtime_error& err) {
149 std::cerr << std::format("Error (poafloc): {}\n", err.what());
150 } catch (const git2wrap::runtime_error& err) {
151 std::cerr << std::format("Error (git2wrap): {}\n", err.what());
152 } catch (const std::runtime_error& err) {
153 std::cerr << std::format("Error: {}\n", err.what());
154 } catch (...) {
155 std::cerr << std::format("Unknown error\n");
158 return 0;