Files
SpineParticlesWeb/DateToSpine/src/editor/SpineOutputParser.cpp
T
2026-09-07 23:48:20 +08:00

83 lines
3.0 KiB
C++

#include "editor/SpineOutputParser.hpp"
#include <regex>
namespace dts {
namespace {
std::optional<SpineVersion> firstVersion(
const std::string& text,
const std::regex& expression,
std::string* trailing = nullptr) {
std::smatch match;
if (!std::regex_search(text, match, expression)) {
return std::nullopt;
}
if (trailing && match.size() > 2) {
*trailing = match[2].str();
}
return SpineVersion::parse(match[1].str());
}
} // namespace
EditorProbeResult SpineOutputParser::parse(
const std::filesystem::path& executable,
const ProcessResult& process) const {
EditorProbeResult result;
result.executable = executable;
result.timedOut = process.timedOut;
result.exitCode = process.exitCode;
result.output = process.output;
if (!process.started) {
result.status = EditorProbeStatus::LaunchFailed;
result.message = process.error.empty() ? "Spine process could not be started." : process.error;
return result;
}
static const std::regex launcher(R"(Spine Launcher\s+(\d+\.\d+(?:\.\d+)?))");
static const std::regex launching(
R"((?:Launching:|Starting:)\s*Spine\s+(\d+\.\d+(?:\.\d+)?)(?:\s+([^\r\n]+))?)");
// MSVC's std::regex does not implement std::regex_constants::multiline,
// so instead of relying on the '^' line anchor with the multiline flag,
// search for "Spine <version>" anywhere (regex_search scans the whole text).
static const std::regex directEditor(
R"(Spine\s+(\d+\.\d+(?:\.\d+)?)(?:\s+([^\r\n]+))?)");
result.launcherVersion = firstVersion(process.output, launcher);
result.editorVersion = firstVersion(process.output, launching, &result.edition);
if (!result.editorVersion) {
result.editorVersion = firstVersion(process.output, directEditor, &result.edition);
}
if (!result.launcherVersion && !result.editorVersion) {
result.status = EditorProbeStatus::UnrecognizedOutput;
result.message = "Process started, but its output was not recognized as Spine.";
} else if (process.timedOut) {
result.status = EditorProbeStatus::ObservedButTimedOut;
result.message = "Spine was detected, but the version probe timed out.";
} else if (process.exitCode == 0) {
result.status = EditorProbeStatus::Available;
result.message = "Spine CLI probe succeeded.";
} else {
result.status = EditorProbeStatus::LaunchFailed;
result.message = "Spine was detected, but the process returned a failure code.";
}
return result;
}
std::string toString(EditorProbeStatus status) {
switch (status) {
case EditorProbeStatus::Available: return "available";
case EditorProbeStatus::ObservedButTimedOut: return "observed-but-timed-out";
case EditorProbeStatus::PathMissing: return "path-missing";
case EditorProbeStatus::LaunchFailed: return "launch-failed";
case EditorProbeStatus::UnrecognizedOutput: return "unrecognized-output";
}
return "unknown";
}
} // namespace dts