aboutsummaryrefslogtreecommitdiff
path: root/src/zen/zen.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2025-09-05 13:02:27 +0200
committerGitHub Enterprise <[email protected]>2025-09-05 13:02:27 +0200
commit45b0307d42b22e04cee63467a8fdb898a2d8d552 (patch)
tree905b3eb62af89269be5b15f4c407d900ce86f7f3 /src/zen/zen.cpp
parentAvoid mutating executable paths when copying files during full service instal... (diff)
downloadarchived-zen-45b0307d42b22e04cee63467a8fdb898a2d8d552.tar.xz
archived-zen-45b0307d42b22e04cee63467a8fdb898a2d8d552.zip
refactor zen command return value handling (#487)
- Improvement: Use consistent language for command line argument parsing errors - Improvement: Changed zen command parsing errors to output help first and error last to make it easier to spot the error - Improvement: Refactor zen command return codes to conform to valid Linux range (0-255) kSuccess = 0, kOtherError = 1, kBadInput = 2, kOutOfMemory = 16, kOutOfDisk = 17, kAssertError = 70, kHttpOtherClientError = 80, kHttpCantConnectError = 81, kHttpNotFound = 66, // NotFound(404) kHttpUnauthorized = 77, // Unauthorized(401), kHttpSLLError = 82, kHttpForbidden = 83, // Forbidden(403) kHttpTimeout = 84, // RequestTimeout(408) kHttpConflict = 85, // Conflict(409) kHttpNoHost = 86, kHttpOtherServerError = 90, kHttpInternalServerError = 91, // InternalServerError(500) kHttpServiceUnavailable = 69, // ServiceUnavailable(503) kHttpBadGateway = 92, // BadGateway(502) kHttpGatewayTimeout = 93, // GatewayTimeout(504)
Diffstat (limited to 'src/zen/zen.cpp')
-rw-r--r--src/zen/zen.cpp204
1 files changed, 130 insertions, 74 deletions
diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp
index 240ba2a81..db63624ce 100644
--- a/src/zen/zen.cpp
+++ b/src/zen/zen.cpp
@@ -72,6 +72,35 @@ ZEN_THIRD_PARTY_INCLUDES_END
namespace zen {
+enum class ReturnCode : std::int8_t
+{
+ kSuccess = 0,
+
+ kOtherError = 1,
+
+ kBadInput = 2,
+ kOutOfMemory = 16,
+ kOutOfDisk = 17,
+ kAssertError = 70,
+
+ kHttpOtherClientError = 80,
+ kHttpCantConnectError = 81, // CONNECTION_FAILURE
+ kHttpNotFound = 66, // NotFound(404)
+ kHttpUnauthorized = 77, // Unauthorized(401),
+ kHttpSLLError =
+ 82, // SSL_CONNECT_ERROR, SSL_LOCAL_CERTIFICATE_ERROR, SSL_REMOTE_CERTIFICATE_ERROR, SSL_CACERT_ERROR, GENERIC_SSL_ERROR
+ kHttpForbidden = 83, // Forbidden(403)
+ kHttpTimeout = 84, // NETWORK_RECEIVE_ERROR, NETWORK_SEND_FAILURE, OPERATION_TIMEDOUT, RequestTimeout(408)
+ kHttpConflict = 85, // Conflict(409)
+ kHttpNoHost = 86, // HOST_RESOLUTION_FAILURE, PROXY_RESOLUTION_FAILURE
+
+ kHttpOtherServerError = 90,
+ kHttpInternalServerError = 91, // InternalServerError(500)
+ kHttpServiceUnavailable = 69, // ServiceUnavailable(503)
+ kHttpBadGateway = 92, // BadGateway(502)
+ kHttpGatewayTimeout = 93, // GatewayTimeout(504)
+};
+
ZenCmdCategory DefaultCategory{.Name = "general commands"};
ZenCmdCategory g_UtilitiesCategory{.Name = "utility commands"};
ZenCmdCategory g_ProjectStoreCategory{.Name = "project store commands"};
@@ -101,7 +130,7 @@ ZenCmdBase::ParseOptions(cxxopts::Options& CmdOptions, int argc, char** argv)
}
catch (const std::exception& Ex)
{
- throw zen::OptionParseException(Ex.what());
+ throw zen::OptionParseException(Ex.what(), CmdOptions.help());
}
CmdOptions.show_positional_help();
@@ -127,7 +156,7 @@ ZenCmdBase::ParseOptions(cxxopts::Options& CmdOptions, int argc, char** argv)
First = false;
}
- throw zen::OptionParseException(fmt::format("Invalid arguments: {}", StringBuilder.ToView()));
+ throw zen::OptionParseException(fmt::format("Invalid arguments: {}", StringBuilder.ToView()), {});
}
return true;
@@ -161,62 +190,68 @@ ZenCmdBase::GetSubCommand(cxxopts::Options&,
return argc;
}
-std::string
-ZenCmdBase::FormatHttpResponse(const cpr::Response& Response)
+static ReturnCode
+GetReturnCodeFromHttpResult(int Error, HttpResponseCode ResponseCode)
{
- if (Response.error.code != cpr::ErrorCode::OK)
+ if ((cpr::ErrorCode)Error != cpr::ErrorCode::OK)
{
- if (Response.error.message.empty())
+ switch ((cpr::ErrorCode)Error)
{
- return fmt::format("Request '{}' failed, error code {}", Response.url.str(), static_cast<int>(Response.error.code));
+ case cpr::ErrorCode::CONNECTION_FAILURE:
+ return ReturnCode::kHttpCantConnectError;
+ case cpr::ErrorCode::HOST_RESOLUTION_FAILURE:
+ case cpr::ErrorCode::PROXY_RESOLUTION_FAILURE:
+ return ReturnCode::kHttpNoHost;
+ case cpr::ErrorCode::INTERNAL_ERROR:
+ case cpr::ErrorCode::NETWORK_RECEIVE_ERROR:
+ case cpr::ErrorCode::NETWORK_SEND_FAILURE:
+ case cpr::ErrorCode::OPERATION_TIMEDOUT:
+ return ReturnCode::kHttpTimeout;
+ case cpr::ErrorCode::SSL_CONNECT_ERROR:
+ case cpr::ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR:
+ case cpr::ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR:
+ case cpr::ErrorCode::SSL_CACERT_ERROR:
+ case cpr::ErrorCode::GENERIC_SSL_ERROR:
+ return ReturnCode::kHttpSLLError;
+ default:
+ return ReturnCode::kHttpOtherClientError;
}
- return fmt::format("Request '{}' failed. Reason: '{}' ({})",
- Response.url.str(),
- Response.error.message,
- static_cast<int>(Response.error.code));
}
-
- std::string Content;
- if (auto It = Response.header.find("Content-Type"); It != Response.header.end())
- {
- zen::HttpContentType ContentType = zen::ParseContentType(It->second);
- if (ContentType == zen::HttpContentType::kText)
- {
- Content = Response.text;
- }
- else if (ContentType == zen::HttpContentType::kJSON)
- {
- Content = fmt::format("\n{}", Response.text);
- }
- else if (!Response.text.empty())
- {
- Content = fmt::format("[{}]", MapContentTypeToString(ContentType));
- }
- }
-
- std::string_view ResponseString = zen::ReasonStringForHttpResultCode(
- Response.status_code == static_cast<long>(zen::HttpResponseCode::NoContent) ? static_cast<long>(zen::HttpResponseCode::OK)
- : Response.status_code);
- if (Content.empty())
- {
- return std::string(ResponseString);
- }
-
- return fmt::format("{}: {}", ResponseString, Content);
-}
-
-int
-ZenCmdBase::MapHttpToCommandReturnCode(const cpr::Response& Response)
-{
- if (zen::IsHttpSuccessCode(Response.status_code))
+ else if (IsHttpSuccessCode(ResponseCode))
{
- return 0;
+ return ReturnCode::kSuccess;
}
- if (Response.error.code != cpr::ErrorCode::OK)
+ else
{
- return static_cast<int>(Response.error.code);
+ switch (ResponseCode)
+ {
+ case HttpResponseCode::Unauthorized:
+ return ReturnCode::kHttpUnauthorized;
+ case HttpResponseCode::NotFound:
+ return ReturnCode::kHttpNotFound;
+ case HttpResponseCode::Forbidden:
+ return ReturnCode::kHttpForbidden;
+ case HttpResponseCode::Conflict:
+ return ReturnCode::kHttpConflict;
+ case HttpResponseCode::InternalServerError:
+ return ReturnCode::kHttpInternalServerError;
+ case HttpResponseCode::ServiceUnavailable:
+ return ReturnCode::kHttpServiceUnavailable;
+ case HttpResponseCode::BadGateway:
+ return ReturnCode::kHttpBadGateway;
+ case HttpResponseCode::GatewayTimeout:
+ return ReturnCode::kHttpGatewayTimeout;
+ default:
+ if (ResponseCode >= HttpResponseCode::InternalServerError)
+ {
+ return ReturnCode::kHttpOtherServerError;
+ }
+ else
+ {
+ return ReturnCode::kHttpOtherClientError;
+ }
+ }
}
- return 1;
}
std::string
@@ -945,7 +980,7 @@ main(int argc, char** argv)
printf("\n");
}
- exit(0);
+ return (int)ReturnCode::kSuccess;
}
#if ZEN_USE_SENTRY
@@ -1022,86 +1057,107 @@ main(int argc, char** argv)
{
if (StrCaseCompare(SubCommand.c_str(), CmdInfo.CmdName) == 0)
{
- cxxopts::Options& VerbOptions = CmdInfo.Cmd->Options();
-
try
{
- return CmdInfo.Cmd->Run(GlobalOptions, (int)CommandArgVec.size(), CommandArgVec.data());
+ CmdInfo.Cmd->Run(GlobalOptions, (int)CommandArgVec.size(), CommandArgVec.data());
+ return (int)ReturnCode::kSuccess;
}
catch (const OptionParseException& Ex)
{
- ZEN_CONSOLE_ERROR("Invalid arguments for command '{}': {}\n\n{}", SubCommand, Ex.what(), VerbOptions.help());
- exit(11);
+ ZEN_CONSOLE("{}\n", Ex.m_Help);
+ ZEN_CONSOLE_ERROR("Invalid arguments for command '{}': {}", SubCommand, Ex.what());
+ return (int)ReturnCode::kBadInput;
}
catch (const std::system_error& Ex)
{
if (IsOOD(Ex))
{
ZEN_CONSOLE_ERROR("Operation failed due to out of disk space: {}", Ex.what());
- exit(3);
+ return (int)ReturnCode::kOutOfDisk;
}
else if (IsOOM(Ex))
{
ZEN_CONSOLE_ERROR("Operation failed due to out of memory: {}", Ex.what());
- exit(3);
+ return (int)ReturnCode::kOutOfMemory;
}
else
{
ZEN_CONSOLE_ERROR("Operation failed due to system error: {} ({})\n", Ex.what(), Ex.code() ? Ex.code().value() : 0);
- exit(Ex.code() ? Ex.code().value() : 10);
+ return (int)ReturnCode::kOtherError;
}
}
catch (const HttpClientError& Ex)
{
ZEN_CONSOLE_ERROR("Operation failed due to a http error: {}", Ex.what());
- exit(Ex.m_Error != 0 ? Ex.m_Error : (int)Ex.m_ResponseCode);
+ ReturnCode Result = GetReturnCodeFromHttpResult(Ex.m_Error, Ex.m_ResponseCode);
+ return (int)Result;
+ }
+ catch (const AssertException& Ex)
+ {
+ ZEN_CONSOLE_ERROR("Operation failed due to an assert exception: {}", Ex.FullDescription());
+ return (int)ReturnCode::kAssertError;
+ }
+ catch (const ErrorWithReturnCode& Ex)
+ {
+ ZEN_CONSOLE_ERROR("{}", Ex.what());
+ return Ex.m_ReturnCode;
}
catch (const std::exception& Ex)
{
- ZEN_CONSOLE_ERROR("Operation failed due to: {}\n", Ex.what());
- exit(11);
+ ZEN_CONSOLE_ERROR("{}\n", Ex.what());
+ return (int)ReturnCode::kOtherError;
}
}
}
printf("Unknown command specified: '%s', exiting\n", SubCommand.c_str());
+ return (int)ReturnCode::kBadInput;
}
catch (const OptionParseException& Ex)
{
- std::string HelpMessage = Options.help();
-
- printf("Error parsing program arguments: %s\n\n%s", Ex.what(), HelpMessage.c_str());
-
- return 9;
+ printf("%s\n\n", Ex.m_Help.c_str());
+ printf("Invalid arguments arguments: %s", Ex.what());
+ return (int)ReturnCode::kBadInput;
}
catch (const std::system_error& Ex)
{
if (IsOOD(Ex))
{
printf("Operation failed due to out of disk space: %s", Ex.what());
- return 3;
+ return (int)ReturnCode::kOutOfDisk;
}
else if (IsOOM(Ex))
{
printf("Operation failed due to out of memory: %s", Ex.what());
- return 3;
+ return (int)ReturnCode::kOutOfMemory;
}
else
{
printf("Operation failed due to system error: %s (%d)\n", Ex.what(), Ex.code() ? Ex.code().value() : 0);
- return Ex.code() ? Ex.code().value() : 10;
+ return (int)ReturnCode::kOtherError;
}
}
catch (const HttpClientError& Ex)
{
- printf("Operation failed due to a http error: %s", Ex.what());
- return Ex.m_Error != 0 ? Ex.m_Error : (int)Ex.m_ResponseCode;
+ printf("Error: Operation failed due to a http error: %s", Ex.what());
+ ReturnCode Result = GetReturnCodeFromHttpResult(Ex.m_Error, Ex.m_ResponseCode);
+ return (int)Result;
+ }
+ catch (const AssertException& Ex)
+ {
+ printf("Error: Operation failed due to an assert exception: %s", Ex.FullDescription().c_str());
+ return (int)ReturnCode::kAssertError;
+ }
+ catch (const ErrorWithReturnCode& Ex)
+ {
+ printf("Error: %s", Ex.what());
+ return Ex.m_ReturnCode;
}
catch (const std::exception& Ex)
{
- printf("Operation failed due to: %s\n", Ex.what());
- return 11;
+ printf("Error: %s\n", Ex.what());
+ return (int)ReturnCode::kOtherError;
}
- return 0;
+ return (int)ReturnCode::kSuccess;
}