mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 06:48:12 +00:00
Shell: Move out run_commands and expand_aliases to be Shell member fns
This makes running commands from outside the AST chain easier.
This commit is contained in:
parent
4c3a415dc3
commit
b0ce8d725a
4 changed files with 99 additions and 87 deletions
|
@ -742,79 +742,7 @@ RefPtr<Value> Execute::run(RefPtr<Shell> shell)
|
||||||
if (m_command->would_execute())
|
if (m_command->would_execute())
|
||||||
return m_command->run(shell);
|
return m_command->run(shell);
|
||||||
|
|
||||||
auto initial_commands = m_command->run(shell)->resolve_as_commands(shell);
|
auto commands = shell->expand_aliases(m_command->run(shell)->resolve_as_commands(shell));
|
||||||
decltype(initial_commands) commands;
|
|
||||||
|
|
||||||
Function<void(Command&)> resolve_aliases_and_append = [&](auto& command) {
|
|
||||||
if (!command.argv.is_empty()) {
|
|
||||||
auto alias = shell->resolve_alias(command.argv[0]);
|
|
||||||
if (!alias.is_null()) {
|
|
||||||
auto argv0 = command.argv.take_first();
|
|
||||||
auto subcommand_ast = Parser { alias }.parse();
|
|
||||||
if (subcommand_ast) {
|
|
||||||
while (subcommand_ast->is_execute()) {
|
|
||||||
auto* ast = static_cast<Execute*>(subcommand_ast.ptr());
|
|
||||||
subcommand_ast = ast->command();
|
|
||||||
}
|
|
||||||
RefPtr<Node> substitute = create<Join>(position(), move(subcommand_ast), create<CommandLiteral>(position(), command));
|
|
||||||
for (auto& subst_command : substitute->run(shell)->resolve_as_commands(shell)) {
|
|
||||||
if (!subst_command.argv.is_empty() && subst_command.argv.first() == argv0) // Disallow an alias resolving to itself.
|
|
||||||
commands.append(subst_command);
|
|
||||||
else
|
|
||||||
resolve_aliases_and_append(subst_command);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commands.append(command);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commands.append(command);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commands.append(command);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& command : initial_commands)
|
|
||||||
resolve_aliases_and_append(command);
|
|
||||||
|
|
||||||
Vector<RefPtr<Job>> jobs_to_wait_for;
|
|
||||||
|
|
||||||
auto run_commands = [&](auto& commands) {
|
|
||||||
for (auto& command : commands) {
|
|
||||||
#ifdef EXECUTE_DEBUG
|
|
||||||
dbg() << "Command";
|
|
||||||
for (auto& arg : command.argv)
|
|
||||||
dbg() << "argv: " << arg;
|
|
||||||
for (auto& redir : command.redirections) {
|
|
||||||
if (redir->is_path_redirection()) {
|
|
||||||
auto path_redir = (const PathRedirection*)redir.ptr();
|
|
||||||
dbg() << "redir path " << (int)path_redir->direction << " " << path_redir->path << " <-> " << path_redir->fd;
|
|
||||||
} else if (redir->is_fd_redirection()) {
|
|
||||||
auto fd_redir = (const FdRedirection*)redir.ptr();
|
|
||||||
dbg() << "redir fd " << fd_redir->source_fd << " -> " << fd_redir->dest_fd;
|
|
||||||
} else if (redir->is_close_redirection()) {
|
|
||||||
auto close_redir = (const CloseRedirection*)redir.ptr();
|
|
||||||
dbg() << "close fd " << close_redir->fd;
|
|
||||||
} else {
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
job = shell->run_command(command);
|
|
||||||
|
|
||||||
if (command.should_wait) {
|
|
||||||
shell->block_on_job(job);
|
|
||||||
} else {
|
|
||||||
if (command.is_pipe_source) {
|
|
||||||
jobs_to_wait_for.append(job);
|
|
||||||
} else if (command.should_notify_if_in_background) {
|
|
||||||
if (job)
|
|
||||||
job->set_running_in_background(true);
|
|
||||||
shell->restore_stdin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (m_capture_stdout) {
|
if (m_capture_stdout) {
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
|
@ -860,9 +788,7 @@ RefPtr<Value> Execute::run(RefPtr<Shell> shell)
|
||||||
try_read();
|
try_read();
|
||||||
};
|
};
|
||||||
|
|
||||||
run_commands(commands);
|
for (auto job : shell->run_commands(commands)) {
|
||||||
|
|
||||||
for (auto job : jobs_to_wait_for) {
|
|
||||||
shell->block_on_job(job);
|
shell->block_on_job(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,12 +803,14 @@ RefPtr<Value> Execute::run(RefPtr<Shell> shell)
|
||||||
return create<StringValue>(builder.build(), shell->local_variable_or("IFS", "\n"), shell->options.inline_exec_keep_empty_segments);
|
return create<StringValue>(builder.build(), shell->local_variable_or("IFS", "\n"), shell->options.inline_exec_keep_empty_segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
run_commands(commands);
|
RefPtr<Job> last_job;
|
||||||
for (auto job : jobs_to_wait_for) {
|
|
||||||
|
for (auto& job : shell->run_commands(commands)) {
|
||||||
shell->block_on_job(job);
|
shell->block_on_job(job);
|
||||||
|
last_job = move(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
return create<JobValue>(move(job));
|
return create<JobValue>(move(last_job));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Execute::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
|
void Execute::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
|
||||||
|
@ -1969,7 +1897,7 @@ Vector<String> TildeValue::resolve_as_list(RefPtr<Shell> shell)
|
||||||
return { shell->expand_tilde(builder.to_string()) };
|
return { shell->expand_tilde(builder.to_string()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<RefPtr<Rewiring>, String> CloseRedirection::apply()
|
Result<RefPtr<Rewiring>, String> CloseRedirection::apply() const
|
||||||
{
|
{
|
||||||
return static_cast<RefPtr<Rewiring>>((adopt(*new Rewiring(fd, fd, Rewiring::Close::ImmediatelyCloseDestination))));
|
return static_cast<RefPtr<Rewiring>>((adopt(*new Rewiring(fd, fd, Rewiring::Close::ImmediatelyCloseDestination))));
|
||||||
}
|
}
|
||||||
|
@ -1978,7 +1906,7 @@ CloseRedirection::~CloseRedirection()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<RefPtr<Rewiring>, String> PathRedirection::apply()
|
Result<RefPtr<Rewiring>, String> PathRedirection::apply() const
|
||||||
{
|
{
|
||||||
auto check_fd_and_return = [my_fd = this->fd](int fd, const String& path) -> Result<RefPtr<Rewiring>, String> {
|
auto check_fd_and_return = [my_fd = this->fd](int fd, const String& path) -> Result<RefPtr<Rewiring>, String> {
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
|
|
@ -77,7 +77,7 @@ struct Rewiring : public RefCounted<Rewiring> {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Redirection : public RefCounted<Redirection> {
|
struct Redirection : public RefCounted<Redirection> {
|
||||||
virtual Result<RefPtr<Rewiring>, String> apply() = 0;
|
virtual Result<RefPtr<Rewiring>, String> apply() const = 0;
|
||||||
virtual ~Redirection();
|
virtual ~Redirection();
|
||||||
virtual bool is_path_redirection() const { return false; }
|
virtual bool is_path_redirection() const { return false; }
|
||||||
virtual bool is_fd_redirection() const { return false; }
|
virtual bool is_fd_redirection() const { return false; }
|
||||||
|
@ -87,7 +87,7 @@ struct Redirection : public RefCounted<Redirection> {
|
||||||
struct CloseRedirection : public Redirection {
|
struct CloseRedirection : public Redirection {
|
||||||
int fd { -1 };
|
int fd { -1 };
|
||||||
|
|
||||||
virtual Result<RefPtr<Rewiring>, String> apply() override;
|
virtual Result<RefPtr<Rewiring>, String> apply() const override;
|
||||||
virtual ~CloseRedirection();
|
virtual ~CloseRedirection();
|
||||||
CloseRedirection(int fd)
|
CloseRedirection(int fd)
|
||||||
: fd(fd)
|
: fd(fd)
|
||||||
|
@ -108,7 +108,7 @@ struct PathRedirection : public Redirection {
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
} direction { Read };
|
} direction { Read };
|
||||||
|
|
||||||
virtual Result<RefPtr<Rewiring>, String> apply() override;
|
virtual Result<RefPtr<Rewiring>, String> apply() const override;
|
||||||
virtual ~PathRedirection();
|
virtual ~PathRedirection();
|
||||||
PathRedirection(String path, int fd, decltype(direction) direction)
|
PathRedirection(String path, int fd, decltype(direction) direction)
|
||||||
: path(move(path))
|
: path(move(path))
|
||||||
|
@ -124,7 +124,7 @@ private:
|
||||||
struct FdRedirection : public Redirection
|
struct FdRedirection : public Redirection
|
||||||
, public Rewiring {
|
, public Rewiring {
|
||||||
|
|
||||||
virtual Result<RefPtr<Rewiring>, String> apply() override { return static_cast<RefPtr<Rewiring>>(this); }
|
virtual Result<RefPtr<Rewiring>, String> apply() const override { return static_cast<RefPtr<Rewiring>>(this); }
|
||||||
virtual ~FdRedirection();
|
virtual ~FdRedirection();
|
||||||
FdRedirection(int source, int dest, Rewiring::Close close)
|
FdRedirection(int source, int dest, Rewiring::Close close)
|
||||||
: Rewiring(source, dest, close)
|
: Rewiring(source, dest, close)
|
||||||
|
|
|
@ -271,6 +271,45 @@ Vector<String> Shell::expand_globs(Vector<StringView> path_segments, const Strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<AST::Command> Shell::expand_aliases(Vector<AST::Command> initial_commands)
|
||||||
|
{
|
||||||
|
Vector<AST::Command> commands;
|
||||||
|
|
||||||
|
Function<void(AST::Command&)> resolve_aliases_and_append = [&](auto& command) {
|
||||||
|
if (!command.argv.is_empty()) {
|
||||||
|
auto alias = resolve_alias(command.argv[0]);
|
||||||
|
if (!alias.is_null()) {
|
||||||
|
auto argv0 = command.argv.take_first();
|
||||||
|
auto subcommand_ast = Parser { alias }.parse();
|
||||||
|
if (subcommand_ast) {
|
||||||
|
while (subcommand_ast->is_execute()) {
|
||||||
|
auto* ast = static_cast<AST::Execute*>(subcommand_ast.ptr());
|
||||||
|
subcommand_ast = ast->command();
|
||||||
|
}
|
||||||
|
AST::Node& substitute = *new AST::Join(subcommand_ast->position(), subcommand_ast, *new AST::CommandLiteral(subcommand_ast->position(), command));
|
||||||
|
for (auto& subst_command : substitute.run(*this)->resolve_as_commands(*this)) {
|
||||||
|
if (!subst_command.argv.is_empty() && subst_command.argv.first() == argv0) // Disallow an alias resolving to itself.
|
||||||
|
commands.append(subst_command);
|
||||||
|
else
|
||||||
|
resolve_aliases_and_append(subst_command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commands.append(command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commands.append(command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commands.append(command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto& command : initial_commands)
|
||||||
|
resolve_aliases_and_append(command);
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
String Shell::resolve_path(String path) const
|
String Shell::resolve_path(String path) const
|
||||||
{
|
{
|
||||||
if (!path.starts_with('/'))
|
if (!path.starts_with('/'))
|
||||||
|
@ -349,7 +388,7 @@ int Shell::run_command(const StringView& cmd)
|
||||||
return last_return_code;
|
return last_return_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Job> Shell::run_command(AST::Command& command)
|
RefPtr<Job> Shell::run_command(const AST::Command& command)
|
||||||
{
|
{
|
||||||
FileDescriptionCollector fds;
|
FileDescriptionCollector fds;
|
||||||
|
|
||||||
|
@ -494,6 +533,49 @@ RefPtr<Job> Shell::run_command(AST::Command& command)
|
||||||
return *job;
|
return *job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<RefPtr<Job>> Shell::run_commands(Vector<AST::Command>& commands)
|
||||||
|
{
|
||||||
|
Vector<RefPtr<Job>> jobs_to_wait_for;
|
||||||
|
|
||||||
|
for (auto& command : commands) {
|
||||||
|
#ifdef SH_DEBUG
|
||||||
|
dbg() << "Command";
|
||||||
|
for (auto& arg : command.argv)
|
||||||
|
dbg() << "argv: " << arg;
|
||||||
|
for (auto& redir : command.redirections) {
|
||||||
|
if (redir->is_path_redirection()) {
|
||||||
|
auto path_redir = (const AST::PathRedirection*)redir.ptr();
|
||||||
|
dbg() << "redir path " << (int)path_redir->direction << " " << path_redir->path << " <-> " << path_redir->fd;
|
||||||
|
} else if (redir->is_fd_redirection()) {
|
||||||
|
auto fd_redir = (const AST::FdRedirection*)redir.ptr();
|
||||||
|
dbg() << "redir fd " << fd_redir->source_fd << " -> " << fd_redir->dest_fd;
|
||||||
|
} else if (redir->is_close_redirection()) {
|
||||||
|
auto close_redir = (const AST::CloseRedirection*)redir.ptr();
|
||||||
|
dbg() << "close fd " << close_redir->fd;
|
||||||
|
} else {
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
auto job = run_command(command);
|
||||||
|
|
||||||
|
if (command.should_wait) {
|
||||||
|
block_on_job(job);
|
||||||
|
jobs_to_wait_for.append(job);
|
||||||
|
} else {
|
||||||
|
if (command.is_pipe_source) {
|
||||||
|
jobs_to_wait_for.append(job);
|
||||||
|
} else if (command.should_notify_if_in_background) {
|
||||||
|
if (job)
|
||||||
|
job->set_running_in_background(true);
|
||||||
|
restore_stdin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobs_to_wait_for;
|
||||||
|
}
|
||||||
|
|
||||||
bool Shell::run_file(const String& filename, bool explicitly_invoked)
|
bool Shell::run_file(const String& filename, bool explicitly_invoked)
|
||||||
{
|
{
|
||||||
auto file_result = Core::File::open(filename, Core::File::ReadOnly);
|
auto file_result = Core::File::open(filename, Core::File::ReadOnly);
|
||||||
|
|
|
@ -73,7 +73,8 @@ public:
|
||||||
constexpr static auto global_init_file_path = "/etc/shellrc";
|
constexpr static auto global_init_file_path = "/etc/shellrc";
|
||||||
|
|
||||||
int run_command(const StringView&);
|
int run_command(const StringView&);
|
||||||
RefPtr<Job> run_command(AST::Command&);
|
RefPtr<Job> run_command(const AST::Command&);
|
||||||
|
Vector<RefPtr<Job>> run_commands(Vector<AST::Command>&);
|
||||||
bool run_file(const String&, bool explicitly_invoked = true);
|
bool run_file(const String&, bool explicitly_invoked = true);
|
||||||
bool run_builtin(int argc, const char** argv, int& retval);
|
bool run_builtin(int argc, const char** argv, int& retval);
|
||||||
bool has_builtin(const StringView&) const;
|
bool has_builtin(const StringView&) const;
|
||||||
|
@ -83,6 +84,7 @@ public:
|
||||||
static String expand_tilde(const String&);
|
static String expand_tilde(const String&);
|
||||||
static Vector<String> expand_globs(const StringView& path, StringView base);
|
static Vector<String> expand_globs(const StringView& path, StringView base);
|
||||||
static Vector<String> expand_globs(Vector<StringView> path_segments, const StringView& base);
|
static Vector<String> expand_globs(Vector<StringView> path_segments, const StringView& base);
|
||||||
|
Vector<AST::Command> expand_aliases(Vector<AST::Command>);
|
||||||
String resolve_path(String) const;
|
String resolve_path(String) const;
|
||||||
String resolve_alias(const String&) const;
|
String resolve_alias(const String&) const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue