blob: 3dc7648afee2733a7e45bfc4a4d661ffcf389cdc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/console/actions.h"
#include "src/developer/debug/shared/message_loop.h"
#include "src/lib/files/file.h"
#include "src/lib/files/path.h"
#include "src/lib/fxl/strings/split_string.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
using Option = fxl::CommandLine::Option;
} // namespace
// Action ----------------------------------------------------------------------
Action::Action() = default;
Action::Action(std::string name, Action::ActionFunction action)
: name_(name), action_(std::move(action)) {}
Action::Action(Action&&) = default;
Action& Action::operator=(Action&& other) {
this->name_ = std::move(other.name_);
this->action_ = std::move(other.action_);
return *this;
}
void Action::operator()(const Session& session, Console* console) const {
// The next_action_ chaining will take care of calling the following command
// when the time is due.
action_(*this, session, console);
}
// ActionFlow ------------------------------------------------------------------
void ActionFlow::ScheduleActions(std::vector<Action>&& actions, const Session* session,
Console* console, Callback callback) {
// If there are no actions, we schedule the callback.
if (actions.empty()) {
callback_(Err());
return;
}
// We store the parameters as they will be used in the future.
flow_ = std::move(actions);
session_ = session;
console_ = console;
callback_ = std::move(callback);
// We schedule the first action to run
debug::MessageLoop::Current()->PostTask(FROM_HERE, [&]() {
const auto& action = flow_.front();
action(*session_, console_);
});
}
ActionFlow& ActionFlow::Singleton() {
// We use the global callback function so that the user doesn't have to
// worry about tracking an instance.
static ActionFlow flow;
return flow;
}
ActionFlow::ActionFlow() = default;
void ActionFlow::PostActionCallback(Err err) {
ActionFlow& flow = ActionFlow::Singleton();
// We log the callback
flow.callbacks_.push_back(err);
// If the command wants us to stop processing, we call the complete callback.
if ((err.type() == ErrType::kCanceled) || err.has_error()) {
flow.callback_(err);
return;
}
flow.current_action_index_++;
// In no more actions available, communicate to caller.
if (flow.current_action_index_ >= flow.flow_.size()) {
flow.callback_(Err());
return;
}
// Schedule the next action.
const auto& next_action = flow.current_action();
debug::MessageLoop::Current()->PostTask(FROM_HERE,
[&]() { next_action(*flow.session_, flow.console_); });
}
void ActionFlow::Clear() {
flow_.clear();
current_action_index_ = 0;
session_ = nullptr;
console_ = nullptr;
callback_ = nullptr;
callbacks_.clear();
}
std::vector<Action> CommandsToActions(const std::string& input) {
auto commands = fxl::SplitStringCopy(input, "\n", fxl::kTrimWhitespace, fxl::kSplitWantNonEmpty);
std::vector<Action> result;
for (size_t i = 0; i < commands.size(); i++) {
result.push_back(Action(
commands[i],
[&, cmd = commands[i]](const Action& action, const Session& session, Console* console) {
console->ProcessInputLine(cmd.c_str(), ActionFlow::PostActionCallback, false);
}));
}
return result;
}
Err ScriptFileToActions(const std::string& path, std::vector<Action>* actions) {
std::string contents;
if (!files::ReadFileToString(files::AbsolutePath(path), &contents))
return Err(fxl::StringPrintf("Could not read file \"%s\"", path.c_str()));
for (auto& action : CommandsToActions(contents)) {
actions->push_back(std::move(action));
}
return Err();
}
} // namespace zxdb