1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 17:07:34 +00:00

LibCore: Make Core::command return CommandResult struct

Previously, Core::command only returned a String which contained the
data from stdout.

The CommandResult struct contains the exit code as well as the data
from stdout and stderr.
This commit is contained in:
Itamar 2022-01-07 16:17:19 +02:00 committed by Andreas Kling
parent a4e2d93aa2
commit fbdd6df185
3 changed files with 28 additions and 19 deletions

View file

@ -80,7 +80,10 @@ String GitRepo::command(Vector<String> const& command_parts) const
String GitRepo::command_wrapper(Vector<String> const& command_parts, String const& chdir) String GitRepo::command_wrapper(Vector<String> const& command_parts, String const& chdir)
{ {
return Core::command("git", command_parts, LexicalPath(chdir)); auto result = Core::command("git", command_parts, LexicalPath(chdir));
if (result.is_error() || result.value().exit_code != 0)
return {};
return result.value().stdout;
} }
bool GitRepo::git_is_installed() bool GitRepo::git_is_installed()

View file

@ -18,27 +18,26 @@ namespace Core {
// Only supported in serenity mode because we use `posix_spawn_file_actions_addchdir` // Only supported in serenity mode because we use `posix_spawn_file_actions_addchdir`
#ifdef __serenity__ #ifdef __serenity__
String command(const String& command_string, Optional<LexicalPath> chdir) ErrorOr<CommandResult> command(String const& command_string, Optional<LexicalPath> chdir)
{ {
auto parts = command_string.split(' '); auto parts = command_string.split(' ');
if (parts.is_empty()) if (parts.is_empty())
return {}; return Error::from_string_literal("empty command"sv);
auto program = parts[0]; auto program = parts[0];
parts.remove(0); parts.remove(0);
return command(program, parts, chdir); return command(program, parts, chdir);
} }
String command(const String& program, const Vector<String>& arguments, Optional<LexicalPath> chdir) ErrorOr<CommandResult> command(String const& program, Vector<String> const& arguments, Optional<LexicalPath> chdir)
{ {
int stdout_pipe[2] = {}; int stdout_pipe[2] = {};
int stderr_pipe[2] = {}; int stderr_pipe[2] = {};
if (pipe2(stdout_pipe, O_CLOEXEC)) { if (pipe2(stdout_pipe, O_CLOEXEC)) {
perror("pipe2"); return Error::from_errno(errno);
VERIFY_NOT_REACHED();
} }
if (pipe2(stderr_pipe, O_CLOEXEC)) { if (pipe2(stderr_pipe, O_CLOEXEC)) {
perror("pipe2"); perror("pipe2");
VERIFY_NOT_REACHED(); return Error::from_errno(errno);
} }
auto close_pipes = ScopeGuard([stderr_pipe, stdout_pipe] { auto close_pipes = ScopeGuard([stderr_pipe, stdout_pipe] {
@ -68,9 +67,6 @@ String command(const String& program, const Vector<String>& arguments, Optional<
perror("posix_spawn"); perror("posix_spawn");
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
int wstatus;
waitpid(pid, &wstatus, 0);
posix_spawn_file_actions_destroy(&action);
// close the write-ends so reading wouldn't block // close the write-ends so reading wouldn't block
close(stdout_pipe[1]); close(stdout_pipe[1]);
@ -84,18 +80,21 @@ String command(const String& program, const Vector<String>& arguments, Optional<
} }
return String::copy(result_file->read_all()); return String::copy(result_file->read_all());
}; };
auto stdout = read_all_from_pipe(stdout_pipe);
auto stderr = read_all_from_pipe(stderr_pipe);
if (WEXITSTATUS(wstatus) != 0) { int wstatus { 0 };
waitpid(pid, &wstatus, 0);
posix_spawn_file_actions_destroy(&action);
int exit_code = WEXITSTATUS(wstatus);
if (exit_code != 0) {
# ifdef DBG_FAILED_COMMANDS # ifdef DBG_FAILED_COMMANDS
dbgln("command failed. stderr: {}", read_all_from_pipe(stderr_pipe)); dbgln("command failed. stderr: {}", );
# endif # endif
return {};
} }
auto result = read_all_from_pipe(stdout_pipe); return CommandResult { WEXITSTATUS(wstatus), stdout, stderr };
if (result.is_null())
return "";
return result;
} }
#endif #endif

View file

@ -14,7 +14,14 @@
namespace Core { namespace Core {
// If the executed command fails, the returned String will be in the null state. // If the executed command fails, the returned String will be in the null state.
String command(const String& program, const Vector<String>& arguments, Optional<LexicalPath> chdir);
String command(const String& command_string, Optional<LexicalPath> chdir); struct CommandResult {
int exit_code { 0 };
String stdout;
String stderr;
};
ErrorOr<CommandResult> command(String const& program, Vector<String> const& arguments, Optional<LexicalPath> chdir);
ErrorOr<CommandResult> command(String const& command_string, Optional<LexicalPath> chdir);
} }