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)
{
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()

View file

@ -18,27 +18,26 @@ namespace Core {
// Only supported in serenity mode because we use `posix_spawn_file_actions_addchdir`
#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(' ');
if (parts.is_empty())
return {};
return Error::from_string_literal("empty command"sv);
auto program = parts[0];
parts.remove(0);
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 stderr_pipe[2] = {};
if (pipe2(stdout_pipe, O_CLOEXEC)) {
perror("pipe2");
VERIFY_NOT_REACHED();
return Error::from_errno(errno);
}
if (pipe2(stderr_pipe, O_CLOEXEC)) {
perror("pipe2");
VERIFY_NOT_REACHED();
return Error::from_errno(errno);
}
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");
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(stdout_pipe[1]);
@ -84,18 +80,21 @@ String command(const String& program, const Vector<String>& arguments, Optional<
}
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
dbgln("command failed. stderr: {}", read_all_from_pipe(stderr_pipe));
dbgln("command failed. stderr: {}", );
# endif
return {};
}
auto result = read_all_from_pipe(stdout_pipe);
if (result.is_null())
return "";
return result;
return CommandResult { WEXITSTATUS(wstatus), stdout, stderr };
}
#endif

View file

@ -14,7 +14,14 @@
namespace Core {
// 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);
}