Add sort capability to aos_starter status.
Add FLAGS_sort string flag for user to specify column name to sort on.
Add new SortApplications() helper to key off FLAGS_sort to sort the
vector of ApplicationStatus structs on correct field.
Update GetAllStarterStatus() to call sort helper before printing output.
Change-Id: I914eaabe68bbe44eef5731c98216591bd54d8182
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
diff --git a/aos/starter/starter_cmd.cc b/aos/starter/starter_cmd.cc
index b4d80d8..a076a9d 100644
--- a/aos/starter/starter_cmd.cc
+++ b/aos/starter/starter_cmd.cc
@@ -1,3 +1,4 @@
+#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
@@ -25,6 +26,9 @@
"autocomplete script.");
DEFINE_string(_bash_autocomplete_word, "",
"Internal use: Current word being autocompleted");
+DEFINE_string(sort, "name",
+ "The name of the column to sort processes by. "
+ "Can be \"name\", \"state\", \"pid\", or \"uptime\".");
namespace {
@@ -85,6 +89,105 @@
"Uptime");
}
+std::vector<const aos::starter::ApplicationStatus *> SortApplications(
+ const aos::FlatbufferVector<aos::starter::Status> &status) {
+ std::vector<const aos::starter::ApplicationStatus *> sorted_statuses;
+ for (const aos::starter::ApplicationStatus *app_status :
+ *status.message().statuses()) {
+ sorted_statuses.push_back(app_status);
+ }
+ // If --sort flag not set, then return this unsorted vector as is.
+ if (FLAGS_sort.empty()) {
+ return sorted_statuses;
+ }
+
+ // Convert --sort flag to lowercase for testing below.
+ std::transform(FLAGS_sort.begin(), FLAGS_sort.end(), FLAGS_sort.begin(),
+ tolower);
+
+ // This function is called once for each node being reported upon, so there is
+ // no need to sort on node, it happens implicitly.
+
+ if (FLAGS_sort == "name") {
+ // Sort on name using std::string_view::operator< for lexicographic order.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ return lhs->name()->string_view() < rhs->name()->string_view();
+ });
+ } else if (FLAGS_sort == "state") {
+ // Sort on state first, and then name for apps in same state.
+ // ApplicationStatus::state is an enum, so need to call EnumNameState()
+ // convenience wrapper to convert enum to char*, and then wrap in
+ // std::string_view for lexicographic ordering.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ return (lhs->state() != rhs->state())
+ ? (std::string_view(
+ aos::starter::EnumNameState(lhs->state())) <
+ std::string_view(
+ aos::starter::EnumNameState(rhs->state())))
+ : (lhs->name()->string_view() <
+ rhs->name()->string_view());
+ });
+ } else if (FLAGS_sort == "pid") {
+ // Sort on pid first, and then name for when both apps are not running.
+ // If the app state is STOPPED, then it will not have a pid, so need to test
+ // that first. If only one app is STOPPED, then return Boolean state to put
+ // running apps before stopped.
+ std::sort(sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ if (lhs->state() == aos::starter::State::STOPPED) {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return lhs->name()->string_view() <
+ rhs->name()->string_view();
+ } else {
+ return false;
+ }
+ } else {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return true;
+ } else {
+ return lhs->pid() < rhs->pid();
+ }
+ }
+ });
+ } else if (FLAGS_sort == "uptime") {
+ // Sort on last_start_time first, and then name for when both apps are not
+ // running, or have exact same start time. Only use last_start_time when app
+ // is not STOPPED. If only one app is STOPPED, then return Boolean state to
+ // put running apps before stopped.
+ std::sort(
+ sorted_statuses.begin(), sorted_statuses.end(),
+ [](const aos::starter::ApplicationStatus *lhs,
+ const aos::starter::ApplicationStatus *rhs) {
+ if (lhs->state() == aos::starter::State::STOPPED) {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return lhs->name()->string_view() < rhs->name()->string_view();
+ } else {
+ return false;
+ }
+ } else {
+ if (rhs->state() == aos::starter::State::STOPPED) {
+ return true;
+ } else {
+ return (lhs->last_start_time() == rhs->last_start_time())
+ ? (lhs->name()->string_view() <
+ rhs->name()->string_view())
+ : (lhs->last_start_time() < rhs->last_start_time());
+ }
+ }
+ });
+ } else {
+ std::cerr << "Unknown sort criteria \"" << FLAGS_sort << "\"" << std::endl;
+ exit(1);
+ }
+
+ return sorted_statuses;
+}
+
void PrintApplicationStatus(const aos::starter::ApplicationStatus *app_status,
const aos::monotonic_clock::time_point &time,
const aos::Node *node) {
@@ -116,8 +219,9 @@
const aos::FlatbufferVector<aos::starter::Status> &status =
optional_status->second;
const aos::monotonic_clock::time_point time = optional_status->first;
+ const auto &sorted_statuses = SortApplications(status);
for (const aos::starter::ApplicationStatus *app_status :
- *status.message().statuses()) {
+ sorted_statuses) {
PrintApplicationStatus(app_status, time, node);
}
} else {