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

commit 709e26144f2bd17fda81e65ef982857a18f5b681
parent 312f9530e0548d1fd5e82809d6531696f26b064a
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Thu, 24 Apr 2025 09:01:49 +0200

Continue switching to new version of hemplate

Diffstat:
M CMakePresets.json | +++++++++++++++++++++++++++++ ------------------------
M source/common.cpp | ++++++++++++++++++++++++++++++++++++++++++++++++ ----------------------------------
M source/common.hpp | + -
M source/startgit-index.cpp | +++++++++++++++++++++++++++++++++++++++++++ ---------------------------------------
M source/startgit.cpp | +++++++++++++ ------

5 files changed, 171 insertions(+), 131 deletions(-)


diff --git a/ CMakePresets.json b/ CMakePresets.json

@@ -7,26 +7,25 @@ }, "configurePresets": [ {
"name": "cmake-pedantic",
"name": "dev-mode",
"hidden": true,
"warnings": {
"dev": true,
"deprecated": true,
"uninitialized": true,
"unusedCli": true,
"systemVars": false
},
"errors": {
"dev": true,
"deprecated": true
"cacheVariables": {
"startgit_DEVELOPER_MODE": "ON",
"VCPKG_MANIFEST_FEATURES": "test"
} }, {
"name": "dev-mode",
"name": "vcpkg",
"hidden": true,
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
},
{
"name": "vcpkg-win64-static",
"hidden": true,
"inherits": "cmake-pedantic",
"cacheVariables": {
"startgit_DEVELOPER_MODE": "ON"
"VCPKG_TARGET_TRIPLET": "x64-windows-static-md"
} }, {

@@ -76,7 +75,8 @@ "hidden": true, "cacheVariables": { "CMAKE_CXX_FLAGS": "/sdl /guard:cf /utf-8 /diagnostics:caret /w14165 /w44242 /w44254 /w44263 /w34265 /w34287 /w44296 /w44365 /w44388 /w44464 /w14545 /w14546 /w14547 /w14549 /w14555 /w34619 /w34640 /w24826 /w14905 /w14906 /w14928 /w45038 /W4 /permissive- /volatile:iso /Zc:inline /Zc:preprocessor /Zc:enumTypes /Zc:lambda /Zc:__cplusplus /Zc:externConstexpr /Zc:throwingNew /EHsc",
"CMAKE_EXE_LINKER_FLAGS": "/machine:x64 /guard:cf"
"CMAKE_EXE_LINKER_FLAGS": "/machine:x64 /guard:cf",
"CMAKE_SHARED_LINKER_FLAGS": "/machine:x64 /guard:cf"
} }, {

@@ -92,7 +92,10 @@ "name": "ci-darwin", "inherits": ["flags-appleclang", "ci-std"], "generator": "Xcode",
"hidden": true
"hidden": true,
"cacheVariables": {
"CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE": "PRE_TEST"
}
}, { "name": "ci-win64",

@@ -109,14 +112,15 @@ "cacheVariables": { "ENABLE_COVERAGE": "ON", "CMAKE_BUILD_TYPE": "Coverage",
"CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage -fkeep-inline-functions -fkeep-static-functions",
"CMAKE_CXX_FLAGS_COVERAGE": "-O0 -g --coverage -fkeep-inline-functions -fkeep-static-functions",
"CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage",
"CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage"
"CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage",
"CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug;"
} }, { "name": "ci-coverage",
"inherits": ["coverage-linux", "dev-mode"],
"inherits": ["coverage-linux", "dev-mode", "vcpkg"],
"cacheVariables": { "COVERAGE_HTML_COMMAND": "" }

@@ -124,10 +128,11 @@ { "name": "ci-sanitize", "binaryDir": "${sourceDir}/build/sanitize",
"inherits": ["ci-linux", "dev-mode"],
"inherits": ["ci-linux", "dev-mode", "vcpkg"],
"cacheVariables": { "CMAKE_BUILD_TYPE": "Sanitize",
"CMAKE_CXX_FLAGS_SANITIZE": "-U_FORTIFY_SOURCE -O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common"
"CMAKE_CXX_FLAGS_SANITIZE": "-U_FORTIFY_SOURCE -O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common",
"CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug;"
} }, {

@@ -145,15 +150,15 @@ }, { "name": "ci-macos",
"inherits": ["ci-build", "ci-darwin", "dev-mode", "ci-multi-config"]
"inherits": ["ci-build", "ci-darwin", "dev-mode", "ci-multi-config", "vcpkg"]
}, { "name": "ci-ubuntu",
"inherits": ["ci-build", "ci-linux", "clang-tidy", "cppcheck", "dev-mode"]
"inherits": ["ci-build", "ci-linux", "clang-tidy", "vcpkg", "cppcheck", "dev-mode"]
}, { "name": "ci-windows",
"inherits": ["ci-build", "ci-win64", "dev-mode", "ci-multi-config"]
"inherits": ["ci-build", "ci-win64", "dev-mode", "ci-multi-config", "vcpkg", "vcpkg-win64-static"]
} ] }

diff --git a/ source/common.cpp b/ source/common.cpp

@@ -2,7 +2,7 @@ #include "common.hpp"
#include <hemplate/classes.hpp>
#include <hemplate/html.hpp>
#include "arguments.hpp"

@@ -10,67 +10,91 @@ namespace startgit { void write_header(std::ostream& ost,
const std::string& title,
const std::string& title_txt,
const std::string& description, const std::string& author, const std::string& relpath, bool has_feed) {
using namespace hemplate; // NOLINT
using namespace hemplate::html; // NOLINT
using hemplate::html::div;
using hemplate::html::link;
ost << html::doctype();
ost << html::html().set("lang", "en");
ost << html::head();
ost << html::title(title);
ost << doctype();
ost << html({{"lang", "en"}});
ost << head();
ost << title(title_txt);
// Meta tags
ost << html::meta({{"charset", "UTF-8"}});
ost << html::meta({{"name", "author"}, {"content", author}});
ost << html::meta({{"name", "description"}, {"content", description}});
ost << meta({{"charset", "UTF-8"}});
ost << meta({{"name", "author"}, {"content", author}});
ost << meta({{"name", "description"}, {"content", description}});
ost << html::meta({{"content", "width=device-width, initial-scale=1"},
{"name", "viewport"}});
ost << meta({
{"content", "width=device-width, initial-scale=1"},
{"name", "viewport"},
});
// Stylesheets
ost << html::link({{"rel", "stylesheet"}, {"type", "text/css"}})
.set("href", args.resource_url + "/css/index.css");
ost << html::link({{"rel", "stylesheet"}, {"type", "text/css"}})
.set("href", args.resource_url + "/css/colors.css");
ost << link({
{"rel", "stylesheet"},
{"type", "text/css"},
{"href", args.resource_url + "/css/index.css"},
});
ost << link({
{"rel", "stylesheet"},
{"type", "text/css"},
{"href", args.resource_url + "/css/colors.css"},
});
if (has_feed) { // Rss feed
ost << html::link({{"rel", "alternate"},
{"type", "application/atom+xml"},
{"title", "RSS feed"},
{"href", relpath + "rss.xml"}});
ost << link({
{"rel", "alternate"},
{"type", "application/atom+xml"},
{"title", "RSS feed"},
{"href", relpath + "rss.xml"},
});
// Atom feed
ost << html::link({{"rel", "alternate"},
{"type", "application/atom+xml"},
{"title", "Atom feed"},
{"href", relpath + "atom.xml"}});
ost << link({
{"rel", "alternate"},
{"type", "application/atom+xml"},
{"title", "Atom feed"},
{"href", relpath + "atom.xml"},
});
} // Icons
ost << html::link({{"rel", "icon"}, {"type", "image/png"}})
.set("sizes", "32x32")
.set("href", args.resource_url + "/img/favicon-32x32.png");
ost << html::link({{"rel", "icon"}, {"type", "image/png"}})
.set("sizes", "16x16")
.set("href", args.resource_url + "/img/favicon-16x16.png");
ost << html::head();
ost << html::body();
ost << html::input()
.set("type", "checkbox")
.set("id", "theme_switch")
.set("class", "theme_switch");
ost << html::div().set("id", "content");
html::div().tgl_state();
ost << html::main();
ost << html::label(" ")
.set("for", "theme_switch")
.set("class", "switch_label");
ost << link({
{"rel", "icon"},
{"type", "image/png"},
{"sizes", "32x32"},
{"href", args.resource_url + "/img/favicon-32x32.png"},
});
ost << link({
{"rel", "icon"},
{"type", "image/png"},
{"sizes", "16x16"},
{"href", args.resource_url + "/img/favicon-16x16.png"},
});
ost << head();
ost << body();
ost << input({
{"type", "checkbox"},
{"id", "theme_switch"},
{"class", "theme_switch"},
});
ost << div({{"id", "content"}});
div().tgl_state();
ost << main();
ost << label({
{"for", "theme_switch"},
{"class", "switch_label"},
});
} void write_header(std::ostream& ost,

@@ -93,23 +117,23 @@ void write_header(std::ostream& ost, void write_footer(std::ostream& ost) {
using namespace hemplate; // NOLINT
using namespace hemplate::html; // NOLINT
using hemplate::html::div;
ost << html::main();
ost << main();
html::div().tgl_state();
ost << html::div();
div().tgl_state();
ost << div();
const auto jss = args.resource_url + "/scripts/main.js";
ost << html::script(" ").set("src", jss);
ost << html::script(
ost << script({{"src", args.resource_url + "/scripts/main.js"}});
ost << script(
"function switchPage(value) {" " let arr = window.location.href.split('/');" " arr[4] = value;" " history.replaceState(history.state, '', arr.join('/'));" " location.reload();" "}");
ost << html::style(
ost << style(
" table { " " margin-left: 0;" " background-color: inherit;"

@@ -126,8 +150,8 @@ void write_footer(std::ostream& ost) "} .del {" " color: var(--theme_red);" "}");
ost << html::body();
ost << html::html();
ost << body();
ost << html();
} } // namespace startgit

diff --git a/ source/common.hpp b/ source/common.hpp

@@ -10,7 +10,7 @@ namespace startgit { void write_header(std::ostream& ost,
const std::string& title,
const std::string& title_txt,
const std::string& description, const std::string& author, const std::string& relpath = "./",

diff --git a/ source/startgit-index.cpp b/ source/startgit-index.cpp

@@ -4,7 +4,7 @@ #include <git2wrap/error.hpp> #include <git2wrap/libgit2.hpp>
#include <hemplate/classes.hpp>
#include <hemplate/html.hpp>
#include <poafloc/poafloc.hpp> #include "arguments.hpp"

@@ -93,7 +93,7 @@ static const poafloc::arg_t arg { int main(int argc, char* argv[]) {
using namespace hemplate; // NOLINT
using namespace hemplate::html; // NOLINT
using namespace startgit; // NOLINT if (poafloc::parse(&arg, argc, argv, 0, &args) != 0) {

@@ -116,50 +116,54 @@ int main(int argc, char* argv[]) "./", /*has_feed=*/false);
ofs << html::h1(args.title);
ofs << html::p(args.description);
ofs << html::table();
ofs << html::thead();
ofs << html::tr()
.add(html::td("Name"))
.add(html::td("Description"))
.add(html::td("Owner"))
.add(html::td("Last commit"));
ofs << html::thead();
ofs << html::tbody();
for (const auto& repo_path : args.repos) {
try {
const repository repo(repo_path);
for (const auto& branch : repo.get_branches()) {
if (branch.get_name() != "master") {
continue;
}
const auto url = repo.get_name() + "/master/log.html";
ofs << html::tr()
.add(html::td().add(
html::a(repo.get_name()).set("href", url)))
.add(html::td(repo.get_description()))
.add(html::td(repo.get_owner()))
.add(html::td(branch.get_commits()[0].get_time()));
goto next;
}
std::cerr << std::format("Warning: {} doesn't have master branch\n",
repo.get_path().string());
next:;
} catch (const git2wrap::error<git2wrap::error_code_t::ENOTFOUND>& err) {
std::cerr << std::format("Warning: {} is not a repository\n",
repo_path.string());
}
}
ofs << html::tbody();
ofs << html::table();
ofs << h1(args.title);
ofs << p(args.description);
ofs << table {
thead {
tr {
td {"Name"},
td {"Description"},
td {"Owner"},
td {"Last commit"},
},
},
tbody {
transform(args.repos,
[](const auto& repo_path) -> element
{
using git2wrap::error_code_t::ENOTFOUND;
try {
const repository repo(repo_path);
for (const auto& branch : repo.get_branches()) {
if (branch.get_name() != "master") {
continue;
}
const auto url =
repo.get_name() + "/master/log.html";
return tr {
td {a {{{"href", url}}, repo.get_name()}},
td {repo.get_description()},
td {repo.get_owner()},
td {branch.get_commits()[0].get_time()},
};
}
std::cerr << std::format(
"Warning: {} doesn't have master branch\n",
repo.get_path().string());
} catch (const git2wrap::error<ENOTFOUND>& err) {
std::cerr << std::format(
"Warning: {} is not a repository\n",
repo_path.string());
}
return text();
}),
},
};
write_footer(ofs); } catch (const git2wrap::runtime_error& err) {

diff --git a/ source/startgit.cpp b/ source/startgit.cpp

@@ -8,7 +8,9 @@ #include <git2wrap/error.hpp> #include <git2wrap/libgit2.hpp>
#include <hemplate/classes.hpp>
#include <hemplate/atom.hpp>
#include <hemplate/html.hpp>
#include <hemplate/rss.hpp>
#include <poafloc/poafloc.hpp> #include "arguments.hpp"

@@ -24,7 +26,7 @@ template<std::ranges::forward_range R> void wtable(std::ostream& ost, std::initializer_list<std::string_view> head, const R& range,
hemplate::procedure<std::ranges::range_value_t<R>> auto proc)
based::Procedure<std::ranges::range_value_t<R>> auto proc)
{ using namespace hemplate::html; // NOLINT

@@ -513,11 +515,16 @@ void write_atom(std::ostream& ost, using namespace hemplate::atom; // NOLINT using hemplate::atom::link;
const hemplate::attributeList self = {{"rel", "self"},
{"href", base_url + "/atom.xml"}};
const hemplate::attribute_list self = {
{"href", base_url + "/atom.xml"},
{"rel", "self"},
};
const hemplate::attributeList alter = {
{"href", args.resource_url}, {"rel", "alternate"}, {"type", "text/html"}};
const hemplate::attribute_list alter = {
{"href", args.resource_url},
{"rel", "alternate"},
{"type", "text/html"},
};
ost << feed { title {args.title},