Crafter.Review/project.cpp

103 lines
4.6 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
import std;
import Crafter.Build;
// Pinned: the Flatpak builds with the base app's crafter-build, which can be
// older than the rules' master. Move the pin together with the base.
#pragma crafter dependency "https://forgejo.catcrafts.net/Catcrafts/Crafter.LintRules.git" commit "7d932892017800b4e1f1a15fe7aa49b3daee9ceb"
import Crafter.LintRules;
namespace fs = std::filesystem;
using namespace Crafter;
namespace {
// The umbrella, then the partitions in import order: each after the ones
// it imports, which is also the order the module map in AGENTS.md uses.
constexpr std::array<std::string_view, 7> Interfaces = {
"interfaces/Crafter.Review",
"interfaces/Crafter.Review-Unicode",
"interfaces/Crafter.Review-Json",
"interfaces/Crafter.Review-Text",
"interfaces/Crafter.Review-Crypto",
"interfaces/Crafter.Review-Core",
"interfaces/Crafter.Review-Driver",
};
constexpr std::array<std::string_view, 4> Implementations = {
"implementations/Crafter.Review-Text",
"implementations/Crafter.Review-Crypto",
"implementations/Crafter.Review-Core",
"implementations/Crafter.Review-Driver",
};
// One per directory under tests/, each an ordinary main() that links the
// library: exit 0 passes, nonzero fails, 77 skips.
constexpr std::array<std::string_view, 2> Tests = {
"Crypto",
"Text",
};
// The version the binary reports: CI sets it from the tag, a checkout
// describes itself, anything else is a development build. A define on
// the library, so each version is its own library variant.
std::string Version() {
if (const char* env = std::getenv("CRAFTER_REVIEW_VERSION"); env && *env) return env;
auto described = RunCommandWithTimeout("git describe --tags --always --dirty --exclude=latest 2>/dev/null", std::chrono::seconds(10));
std::string version = described.output;
while (!version.empty() && (version.back() == '\n' || version.back() == '\r')) version.pop_back();
if (described.exitCode != 0 || version.empty()) return "0.0.0-dev";
return version;
}
}
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
// Crafter.Network for its TCP and HTTP/1.1 clients and listener, without
// QUIC: msquic is most of a fresh build and nothing here speaks HTTP/3.
// From forgejo at a pinned commit, or with --local from the checkout next
// to this one (which is also how Crafter.Network then finds
// Crafter.Thread).
std::vector<std::string> depArgs(args.begin(), args.end());
depArgs.emplace_back("--no-quic");
const bool useLocal = std::ranges::find(args, std::string_view("--local")) != args.end();
Configuration* network = useLocal
? LocalProject({ .projectFile = "../Crafter.Network/project.cpp", .args = depArgs })
: GitProject({
.source = { .url = "https://forgejo.catcrafts.net/Catcrafts/Crafter.Network.git", .commit = "f68321685006be65f6bc0436fd0175611f1e0a55" },
.args = depArgs,
});
static auto ReviewLib = std::make_unique<Configuration>();
ReviewLib->path = "./";
ReviewLib->name = "crafter.review-lib";
ReviewLib->outputName = "crafter-review";
ApplyStandardArgs(*ReviewLib, args);
ReviewLib->type = ConfigurationType::LibraryStatic;
ReviewLib->dependencies = { network };
// Backslash-escaped quotes: the define travels through the shell before
// it reaches clang, which must still see a string literal.
ReviewLib->defines.push_back({"CRAFTER_REVIEW_VERSION", std::format("\\\"{}\\\"", Version())});
{
std::vector<fs::path> interfaces(Interfaces.begin(), Interfaces.end());
std::vector<fs::path> implementations(Implementations.begin(), Implementations.end());
ReviewLib->GetInterfacesAndImplementations(interfaces, implementations);
}
Configuration cfg;
cfg.path = "./";
cfg.name = "crafter.review-exe";
cfg.outputName = "crafter-review";
ApplyStandardArgs(cfg, args);
cfg.type = ConfigurationType::Executable;
cfg.dependencies = { ReviewLib.get() };
{
std::array<fs::path, 0> interfaces = {};
std::array<fs::path, 1> implementations = { "implementations/main" };
cfg.GetInterfacesAndImplementations(interfaces, implementations);
}
for (const std::string_view test : Tests) {
cfg.AddTest(test).Dependencies({ ReviewLib.get() });
}
LintRules::AddLiteRules(cfg);
return cfg;
}