startgitStatic 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 (4675B)
0 #include <format> 1 #include <fstream> 2 #include <iostream> 3 4 #include <git2wrap/error.hpp> 5 #include <git2wrap/libgit2.hpp> 6 #include <hemplate/html.hpp> 7 #include <poafloc/poafloc.hpp> 8 9 #include "arguments.hpp" 10 #include "document.hpp" 11 #include "repository.hpp" 12 namespace startgit 13 { 14 15 hemplate::element write_table_row(const std::filesystem::path& repo_path) 16 { 17 using namespace hemplate::html; // NOLINT 18 19 try { 20 const repository repo(repo_path); 21 22 for (const auto& branch : repo.get_branches()) { 23 if (branch.get_name() != "master") { 24 continue; 25 } 26 27 const auto url = repo.get_name() + "/master/log.html"; 28 return tr { 29 td {aHref {url, repo.get_name()}}, 30 td {repo.get_description()}, 31 td {repo.get_owner()}, 32 td {branch.get_commits()[0].get_time()}, 33 }; 34 } 35 36 std::cerr << std::format( 37 "Warning: {} doesn't have master branch\n", repo.get_path().string() 38 ); 39 } catch (const git2wrap::error<git2wrap::error_code_t::ENOTFOUND>& err) { 40 std::cerr << std::format( 41 "Warning: {} is not a repository\n", repo_path.string() 42 ); 43 } 44 45 return element {}; 46 } 47 48 hemplate::element write_table() 49 { 50 using namespace hemplate::html; // NOLINT 51 52 return element { 53 h1 {args.title}, 54 p {args.description}, 55 table { 56 thead { 57 tr { 58 td {"Name"}, 59 td {"Description"}, 60 td {"Owner"}, 61 td {"Last commit"}, 62 }, 63 }, 64 tbody { 65 transform(args.repos, write_table_row), 66 }, 67 } 68 }; 69 } 70 71 } // namespace startgit 72 73 namespace 74 { 75 76 int parse_opt(int key, const char* arg, poafloc::Parser* parser) 77 { 78 auto* l_args = static_cast<startgit::arguments_t*>(parser->input()); 79 switch (key) { 80 case 'o': 81 l_args->output_dir = arg; 82 break; 83 case 'b': 84 l_args->base_url = arg; 85 if (l_args->base_url.back() == '/') { 86 l_args->base_url.pop_back(); 87 } 88 break; 89 case 'r': 90 l_args->resource_url = arg; 91 if (l_args->resource_url.back() == '/') { 92 l_args->resource_url.pop_back(); 93 } 94 break; 95 case 'a': 96 l_args->author = arg; 97 break; 98 case 'd': 99 l_args->description = arg; 100 break; 101 case 'f': 102 l_args->force = true; 103 break; 104 case poafloc::ARG: 105 try { 106 l_args->repos.emplace_back(std::filesystem::canonical(arg)); 107 } catch (const std::filesystem::filesystem_error& arr) { 108 std::cerr << std::format("Warning: {} doesn't exist\n", arg); 109 } 110 break; 111 case poafloc::END: 112 if (l_args->repos.empty()) { 113 std::cerr << std::format("Error: no repositories provided\n"); 114 return -1; 115 } 116 break; 117 case poafloc::ERROR: 118 poafloc::help(parser, stderr, poafloc::STD_ERR); 119 break; 120 default: 121 break; 122 } 123 return 0; 124 } 125 126 // NOLINTBEGIN 127 // clang-format off 128 static const poafloc::option_t options[] = { 129 {0, 0, 0, 0, "Output mode", 1}, 130 {"output", 'o', "DIR", 0, "Output directory"}, 131 {"force", 'f', 0, 0, "Force write even if file exists"}, 132 {0, 0, 0, 0, "General information", 2}, 133 {"base", 'b', "URL", 0, "Absolute destination URL"}, 134 {"resource", 'r', "URL", 0, "URL that houses styles and scripts"}, 135 {"author", 'a', "NAME", 0, "Owner of the repository"}, 136 {"title", 't', "TITLE", 0, "Title for the index page"}, 137 {"description", 'd', "DESC", 0, "Description for the index page"}, 138 {0, 0, 0, 0, "Informational Options", -1}, 139 {0}, 140 }; 141 // clang-format on 142 143 static const poafloc::arg_t arg { 144 options, 145 parse_opt, 146 "repositories...", 147 "", 148 }; 149 // NOLINTEND 150 151 } // namespace 152 153 int main(int argc, char* argv[]) 154 { 155 using namespace hemplate::html; // NOLINT 156 using namespace startgit; // NOLINT 157 158 if (poafloc::parse(&arg, argc, argv, 0, &args) != 0) { 159 std::cerr << "There was an error while parsing arguments\n"; 160 return 1; 161 } 162 163 try { 164 const git2wrap::libgit2 libgit; 165 166 auto& output_dir = args.output_dir; 167 std::filesystem::create_directories(output_dir); 168 output_dir = std::filesystem::canonical(output_dir); 169 170 std::ofstream ofs(args.output_dir / "index.html"); 171 const document doc { 172 args.title, args.description, args.author, "./", /* has_feed = */ false 173 }; 174 doc.render(ofs, write_table); 175 176 } catch (const git2wrap::runtime_error& err) { 177 std::cerr << std::format("Error (git2wrap): {}\n", err.what()); 178 } catch (const std::runtime_error& err) { 179 std::cerr << std::format("Error: {}\n", err.what()); 180 } catch (...) { 181 std::cerr << std::format("Unknown error\n"); 182 } 183 184 return 0; 185 }