power-utils: Add --compare option
This option is to get a latest version from a list of PSU versions.
Due to the --compare option requires a list of strings and only one
option is supported at the same time, it's easier to switch to CLI11 to
parse the arguments.
Also add --raw option that outputs the text without linefeed.
Tested: Verify both --get-version and --compare works on Witherspoon.
Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: Idec75e3a5699eba8ba587e74824431993fe10c4c
diff --git a/tools/power-utils/argument.cpp b/tools/power-utils/argument.cpp
deleted file mode 100644
index 570c97f..0000000
--- a/tools/power-utils/argument.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Copyright © 2019 IBM Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "argument.hpp"
-
-#include <algorithm>
-#include <iostream>
-#include <iterator>
-
-namespace phosphor
-{
-namespace power
-{
-
-void ArgumentParser::usage(char** argv)
-{
- std::cerr << "Usage: " << argv[0] << " [options] <psu-inventory-path>\n";
- std::cerr << "Options:\n";
- std::cerr << " --help Print this menu\n";
- std::cerr << " --get-version Get PSU version\n";
- std::cerr << std::flush;
-}
-
-const option ArgumentParser::options[] = {
- {"get-version", required_argument, NULL, 'g'},
- {"help", no_argument, NULL, 'h'},
- {0, 0, 0, 0},
-};
-
-const char* ArgumentParser::optionStr = "g:h?";
-ArgumentParser::ArgumentParser(int argc, char** argv)
-{
- int option = 0;
- while (-1 != (option = getopt_long(argc, argv, optionStr, options, NULL)))
- {
- if ((option == '?') || (option == 'h'))
- {
- usage(argv);
- exit(-1);
- }
-
- auto i = &options[0];
- while ((i->val != option) && (i->val != 0))
- {
- ++i;
- }
-
- if (i->val)
- {
- arguments[i->name] = (i->has_arg ? optarg : trueString);
- }
- }
-}
-
-const std::string& ArgumentParser::operator[](const std::string& opt)
-{
- auto i = arguments.find(opt);
- if (i == arguments.end())
- {
- return emptyString;
- }
- else
- {
- return i->second;
- }
-}
-
-const std::string ArgumentParser::trueString = "true";
-const std::string ArgumentParser::emptyString = "";
-
-} // namespace power
-} // namespace phosphor
diff --git a/tools/power-utils/main.cpp b/tools/power-utils/main.cpp
index e043821..19d0395 100644
--- a/tools/power-utils/main.cpp
+++ b/tools/power-utils/main.cpp
@@ -13,27 +13,45 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "argument.hpp"
#include "version.hpp"
+#include <CLI/CLI.hpp>
#include <phosphor-logging/log.hpp>
-using namespace phosphor::power;
using namespace phosphor::logging;
int main(int argc, char** argv)
{
- ArgumentParser args{argc, argv};
- auto psuPath = args["get-version"];
- if (psuPath.empty())
+
+ std::string psuPath;
+ std::vector<std::string> versions;
+ bool rawOutput = false;
+
+ CLI::App app{"PSU utils app for OpenBMC"};
+ auto action = app.add_option_group("Action");
+ action->add_option("-g,--get-version", psuPath,
+ "Get PSU version from inventory path");
+ action->add_option("-c,--compare", versions,
+ "Compare and get the latest version");
+ action->require_option(1); // Only one option is supported
+ app.add_flag("--raw", rawOutput, "Output raw text without linefeed");
+ CLI11_PARSE(app, argc, argv);
+
+ std::string ret;
+
+ if (!psuPath.empty())
{
- log<level::ERR>("PSU Inventory path argument required");
- args.usage(argv);
- exit(1);
+ ret = version::getVersion(psuPath);
+ }
+ if (!versions.empty())
+ {
+ ret = version::getLatest(versions);
}
- // For now only get-version is supported
- auto version = version::getVersion(psuPath);
- printf("%s", version.c_str());
- return version.empty() ? 1 : 0;
+ printf("%s", ret.c_str());
+ if (!rawOutput)
+ {
+ printf("\n");
+ }
+ return ret.empty() ? 1 : 0;
}
diff --git a/tools/power-utils/meson.build b/tools/power-utils/meson.build
index fa193be..4f0d53f 100644
--- a/tools/power-utils/meson.build
+++ b/tools/power-utils/meson.build
@@ -1,6 +1,5 @@
psutils = executable(
'psutils',
- 'argument.cpp',
'version.cpp',
'main.cpp',
dependencies: [
@@ -13,3 +12,5 @@
libpower,
]
)
+
+subdir('test')
diff --git a/tools/power-utils/test/meson.build b/tools/power-utils/test/meson.build
new file mode 100644
index 0000000..056f4cc
--- /dev/null
+++ b/tools/power-utils/test/meson.build
@@ -0,0 +1,18 @@
+test(
+ 'test_version',
+ executable(
+ 'test_version',
+ 'test_version.cpp',
+ '../version.cpp',
+ dependencies: [
+ gtest,
+ phosphor_logging,
+ ],
+ implicit_include_directories: false,
+ include_directories: '../../..',
+ link_with: [
+ libpower,
+ ],
+ objects: record_manager,
+ )
+)
diff --git a/tools/power-utils/test/test_version.cpp b/tools/power-utils/test/test_version.cpp
new file mode 100644
index 0000000..20ab52b
--- /dev/null
+++ b/tools/power-utils/test/test_version.cpp
@@ -0,0 +1,45 @@
+/**
+ * Copyright © 2019 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../version.hpp"
+
+#include <gtest/gtest.h>
+
+TEST(Version, GetLatest)
+{
+ // Input 2 different version where primary versions are different
+ std::vector<std::string> input = {"00000110", "01100110"};
+ EXPECT_EQ("01100110", version::getLatest(input));
+
+ // Input 3 different version where secondary versions are different
+ input = {"11223366", "11223355", "11223344"};
+ EXPECT_EQ("11223366", version::getLatest(input));
+
+ // Input 3 different version where communication versions are different
+ input = {"111133336666", "111133338888", "111133332222"};
+ EXPECT_EQ("111133338888", version::getLatest(input));
+
+ // Input has 3 same versions
+ input = {"11112222", "11112222", "11112222"};
+ EXPECT_EQ("11112222", version::getLatest(input));
+
+ // Input has one version
+ input = {"11112222"};
+ EXPECT_EQ("11112222", version::getLatest(input));
+
+ // Input empty
+ input = {};
+ EXPECT_EQ("", version::getLatest(input));
+}
diff --git a/tools/power-utils/version.cpp b/tools/power-utils/version.cpp
index 1acbbf2..12bb7c9 100644
--- a/tools/power-utils/version.cpp
+++ b/tools/power-utils/version.cpp
@@ -74,6 +74,21 @@
}
return std::make_tuple(*devicePath, type, versionStr);
}
+
+// A default implemention compare the string itself
+std::string getLatestDefault(const std::vector<std::string>& versions)
+{
+ std::string latest;
+ for (const auto& version : versions)
+ {
+ if (latest < version)
+ {
+ latest = version;
+ }
+ }
+ return latest;
+}
+
} // namespace utils
namespace version
@@ -100,4 +115,25 @@
return version;
}
+std::string getLatest(const std::vector<std::string>& versions)
+{
+ // TODO: when multiple PSU/Machines are supported, add configuration options
+ // to implement machine-specific logic.
+ // For now IBM AC Servers and Inspur FP5280G2 are supported.
+ //
+ // IBM AC servers' PSU version has two types:
+ // * XXXXYYYYZZZZ: XXXX is the primary version
+ // YYYY is the secondary version
+ // ZZZZ is the communication version
+ //
+ // * XXXXYYYY: XXXX is the primary version
+ // YYYY is the seconday version
+ //
+ // Inspur FP5280G2 PSU version is human readable text and a larger string
+ // means a newer version.
+ //
+ // So just compare by strings is OK for these cases
+ return utils::getLatestDefault(versions);
+}
+
} // namespace version
diff --git a/tools/power-utils/version.hpp b/tools/power-utils/version.hpp
index 26f0ce6..c10071a 100644
--- a/tools/power-utils/version.hpp
+++ b/tools/power-utils/version.hpp
@@ -16,6 +16,7 @@
#pragma once
#include <string>
+#include <vector>
namespace version
{
@@ -24,7 +25,18 @@
* Get the software version of the PSU
*
* @param[in] psuInventoryPath - The inventory path of the PSU
+ *
+ * @return The version of the PSU
*/
std::string getVersion(const std::string& psuInventoryPath);
+/**
+ * Get the latest version from a list of versions
+ *
+ * @param[in] versions - The list of PSU version strings
+ *
+ * @return The latest version
+ */
+std::string getLatest(const std::vector<std::string>& versions);
+
} // namespace version