Some checks failed
Secret scan / gitleaks (push) Failing after 12s
Mirror source to Forgejo / mirror (push) Has been skipped
Tests / Static Analysis (push) Has been cancelled
Tests / Warm Conan & ccache (linux-arm64) (push) Has been cancelled
Tests / Warm Conan & ccache (macos-arm64) (push) Has been cancelled
Tests / Warm Conan & ccache (linux-x86_64) (push) Has been cancelled
Tests / Warm Conan & ccache (macos-x86_64) (push) Has been cancelled
Tests / Warm Conan & ccache (windows-x86_64) (push) Has been cancelled
Tests / warm (push) Has been cancelled
Tests / Tests (linux-arm64) (push) Has been cancelled
Tests / Tests (macos-arm64) (push) Has been cancelled
Tests / Tests (linux-x86_64-asan) (push) Has been cancelled
Tests / Tests (linux-x86_64-ubsan) (push) Has been cancelled
Tests / Tests (linux-x86_64) (push) Has been cancelled
Tests / Tests (windows-x86_64) (push) Has been cancelled
* refactor(daemon): one table for repair operation wire codes
The code published under repair_current_operation_code was defined in
three places: a name->code chain in RepairService.cpp, an enum->name
switch beside it, and a code->label switch in the CLI. The two daemon
tables agreed with each other but the CLI copy had already drifted in
wording, and nothing tied the three together.
metric_keys.h now carries the single code<->name table next to the
metric key it describes, with constexpr lookups in both directions.
RepairService's name->code chain delegates to it; the enum->name
switch stays because it is keyed by the private enum. The CLI copy
goes in the next commit with the status renderer.
Signed-off-by: trvon <me@trevon.dev>
* refactor(cli): extract the daemon status renderer
showStatus() in daemon_command.cpp was 1,762 lines: two RPCs, a
bootstrap-file fallback, and two ~400/1,100-line render bodies that
wrote straight to std::cout from inside the command class, reachable
only through a live daemon. The render bodies read nothing from the
command except the expected data directory, the explicit-socket flag,
and a memory-sync fetch they triggered mid-render.
The bodies now live in src/cli/commands/daemon_status_render.cpp as
free functions over StatusResponse plus a small DaemonStatusRenderContext
(configured data dir, explicit-socket flag, optional MemorySyncResponse)
writing to an ostream. The readiness/label helpers that only they used
(humanizeToken, classifyReadiness, isEphemeralDataDir,
daemonDataDirFromStatus, paintStatus, neutralText) move with them.
DaemonCommand keeps the RPCs and the bootstrap fallback; the memory-sync
fetch becomes fetchMemorySyncStatus() and runs just before rendering
instead of in the middle of it, so the section prints in the same place
with the same bounded 3 s timeout.
The move is verbatim: after the mechanical substitutions
(std::cout -> os, expectedDataDir() -> ctx.configuredDataDir, the
memory-sync call, the explicit-socket flag, and the repair label
function) the two bodies match the originals character for character
modulo whitespace. The CLI's private repair-operation switch is gone;
the label now comes from the shared table in metric_keys.h with
underscores rendered as spaces, which reproduces the previous wording
("stuck docs", "block refs", "path tree").
tests/unit/cli/daemon_status_render_catch2_test.cpp drives both
renderers and the memory-sync section from synthetic responses:
overview rows, blockers with init progress, last error, data-dir
mismatch (and its suppression under --socket), temporary data dir,
the active repair operation label, every detailed section, and the
started/not-started memory-sync gate.
daemon_command.cpp: 4,082 -> 2,341 lines; daemon_status_render.cpp:
1,642 lines.
Signed-off-by: trvon <me@trevon.dev>
* refactor(app): one home for hash predicates, path aliasing, and metadata qualifiers
Three small helpers had grown parallel copies with quietly different
rules:
- "does this look like a hash" existed four times: search_service
(8-64 hex), document_service (6-63), cat_command (6-64), plus a
never-defined utils::looksLikeHash declaration in services.hpp. The
8 vs 6 threshold is deliberate (D3): a bare query token must reach
8 hex characters before it stops being text, while an explicit hash
argument may be 6. yams/common/hash_predicates.h now names the two
predicates apart (looksLikeHashQueryToken, looksLikePartialHashArgument)
over one isHexDigits; document_service's 6..63 bound was deliberate
for the name resolver (a full 64-hex name must not resolve as a prefix
and delete by hash), so its two resolver sites now guard size() != 64
explicitly, as the partial-hash resolution site already did.
- macOS /private aliasing had three incompatible policies: search
appended the alias of /var only, grep canonicalized /var and /tmp
to the /private spelling, and the delete resolver displayed
/private/var as /var. yams/common/fs_utils.h now carries one alias
table ({/var,/tmp} <-> /private/...) with three lexical policies over
it (otherSpelling, canonicalSpelling, displaySpelling) and the
platform-gated wrappers callers use. Declared behavior change, macOS
only: search patterns under /tmp now also match their /private/tmp
spelling, and the resolver displays /private/tmp/... as /tmp/....
- Inline key=value metadata filters were parsed twice: SearchService's
extractStructuredMetadataQuery (exactly one '=', no quoting/grouping
characters, deduplicated by key) and SearchEngine's
parseMetadataFiltersFromQuery (any '=' token, duplicates kept). The
stricter, tested parser moves into yams/search/query_qualifiers.hpp
and both call it. Declared behavior change for the hybrid metadata
component: tokens like name="x" or a=b=c stay in the query instead
of becoming filters, and repeated keys collapse to the last value.
Tests: hash_predicates_catch2_test.cpp pins both thresholds and the
64-character bound; path_alias_catch2_test.cpp pins the alias table,
the three policies, and the platform gating; query_qualifiers_catch2_test.cpp
gains the structured-metadata cases (split, dedupe, malformed tokens,
filters-only). search_service, document_service, grep_service,
service_utilities, and resolve_submodule pass unchanged. Portability
allowlist anchors reflowed for the four files whose lines moved.
Signed-off-by: trvon <me@trevon.dev>
* fix(cli): flush status before optional collection
Render useful primary status before waiting for memory-sync details.
Keep both brief and detailed paths behind the tested ordering seam.
Signed-off-by: trvon <me@trevon.dev>
---------
Signed-off-by: trvon <me@trevon.dev>
64 lines
2.7 KiB
C++
64 lines
2.7 KiB
C++
// macOS spells /var and /tmp as symlinks into /private. Documents can be indexed under either
|
|
// spelling, so every consumer that compares, displays, or expands paths must agree on one alias
|
|
// table. These tests pin that table and the three policies built on it.
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
|
|
#include <yams/common/fs_utils.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using yams::common::path_alias::canonicalSpelling;
|
|
using yams::common::path_alias::displaySpelling;
|
|
using yams::common::path_alias::otherSpelling;
|
|
|
|
TEST_CASE("otherSpelling maps between the /private and short forms of var and tmp",
|
|
"[common][fs][alias][catch2]") {
|
|
CHECK(otherSpelling("/var") == "/private/var");
|
|
CHECK(otherSpelling("/var/folders/x") == "/private/var/folders/x");
|
|
CHECK(otherSpelling("/private/var") == "/var");
|
|
CHECK(otherSpelling("/private/var/folders/x") == "/var/folders/x");
|
|
CHECK(otherSpelling("/tmp") == "/private/tmp");
|
|
CHECK(otherSpelling("/tmp/a.txt") == "/private/tmp/a.txt");
|
|
CHECK(otherSpelling("/private/tmp/a.txt") == "/tmp/a.txt");
|
|
|
|
SECTION("only whole path components alias") {
|
|
CHECK(otherSpelling("/variable/x").empty());
|
|
CHECK(otherSpelling("/tmpfs/x").empty());
|
|
CHECK(otherSpelling("/private/varnish").empty());
|
|
CHECK(otherSpelling("/home/user/var/x").empty());
|
|
CHECK(otherSpelling("").empty());
|
|
CHECK(otherSpelling("relative/var/x").empty());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("canonical spelling is the /private form and display spelling is the short form",
|
|
"[common][fs][alias][catch2]") {
|
|
CHECK(canonicalSpelling("/var/folders/x") == "/private/var/folders/x");
|
|
CHECK(canonicalSpelling("/tmp/a") == "/private/tmp/a");
|
|
CHECK(canonicalSpelling("/private/tmp/a") == "/private/tmp/a");
|
|
CHECK(canonicalSpelling("/usr/local/a") == "/usr/local/a");
|
|
|
|
CHECK(displaySpelling("/private/var/folders/x") == "/var/folders/x");
|
|
CHECK(displaySpelling("/private/tmp/a") == "/tmp/a");
|
|
CHECK(displaySpelling("/tmp/a") == "/tmp/a");
|
|
CHECK(displaySpelling("/usr/local/a") == "/usr/local/a");
|
|
}
|
|
|
|
TEST_CASE("platform wrappers alias only on macOS", "[common][fs][alias][catch2]") {
|
|
const std::string canon = yams::common::canonicalizeMacPathAlias("/var/x");
|
|
const std::string disp = yams::common::displayMacPathAlias("/private/var/x");
|
|
std::vector<std::string> patterns{"/var/x", "/usr/y"};
|
|
yams::common::appendMacPathAliases(patterns);
|
|
#if defined(__APPLE__)
|
|
CHECK(canon == "/private/var/x");
|
|
CHECK(disp == "/var/x");
|
|
REQUIRE(patterns.size() == 3);
|
|
CHECK(patterns[2] == "/private/var/x");
|
|
#else
|
|
CHECK(canon == "/var/x");
|
|
CHECK(disp == "/private/var/x");
|
|
CHECK(patterns.size() == 2);
|
|
#endif
|
|
}
|