Merge "Change the format of header-abi-diff config from .ini to .json" am: e43c2bc9a7 am: 1997b594d6

Original change: https://android-review.googlesource.com/c/platform/development/+/2176545

Change-Id: I6b97bbb31b9171d2b6f1fbc7a4f50c821f042b00
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Mu-Le Lee
2022-08-17 06:54:26 +00:00
committed by Automerger Merge Worker
5 changed files with 78 additions and 175 deletions

View File

@@ -127,6 +127,10 @@ cc_binary_host {
"src/diff/abi_diff_wrappers.cpp",
"src/diff/header_abi_diff.cpp",
],
static_libs: [
"libjsoncpp",
],
}
cc_library_host_static {
@@ -197,6 +201,7 @@ cc_test_host {
"libgtest",
"libgtest_main",
"libheader-checker",
"libjsoncpp",
],
shared_libs: [

View File

@@ -15,7 +15,6 @@
#include "diff/abi_diff.h"
#include "utils/config_file.h"
#include "utils/string_utils.h"
#include <llvm/ADT/SmallString.h>
#include <llvm/Support/CommandLine.h>
@@ -31,8 +30,6 @@ using header_checker::repr::CompatibilityStatusIR;
using header_checker::repr::DiffPolicyOptions;
using header_checker::repr::TextFormatIR;
using header_checker::utils::ConfigFile;
using header_checker::utils::ConfigParser;
using header_checker::utils::ParseBool;
static llvm::cl::OptionCategory header_checker_category(
@@ -149,16 +146,19 @@ static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
static std::string GetConfigFilePath(const std::string &dump_file_path) {
llvm::SmallString<128> config_file_path(dump_file_path);
llvm::sys::path::remove_filename(config_file_path);
llvm::sys::path::append(config_file_path, "config.ini");
llvm::sys::path::append(config_file_path, "config.json");
return std::string(config_file_path);
}
static void ReadConfigFile(const std::string &config_file_path) {
ConfigFile cfg = ConfigParser::ParseFile(config_file_path);
ConfigFile cfg;
if (!cfg.Load(config_file_path)) {
::exit(1);
}
if (cfg.HasSection("global")) {
for (auto &&p : cfg.GetSection("global")) {
auto &&key = p.first;
bool value_bool = ParseBool(p.second);
bool value_bool = p.second;
if (key == "allow_adding_removing_weak_symbols") {
allow_adding_removing_weak_symbols = value_bool;
} else if (key == "advice_only") {

View File

@@ -14,10 +14,10 @@
#include "utils/config_file.h"
#include "utils/string_utils.h"
#include <json/json.h>
#include <llvm/Support/raw_ostream.h>
#include <fstream>
#include <map>
#include <string>
@@ -25,61 +25,28 @@ namespace header_checker {
namespace utils {
ConfigFile ConfigParser::ParseFile(std::istream &istream) {
ConfigParser parser(istream);
return parser.ParseFile();
}
ConfigFile ConfigParser::ParseFile(const std::string &path) {
std::ifstream stream(path, std::ios_base::in);
return ParseFile(stream);
}
ConfigFile ConfigParser::ParseFile() {
size_t line_no = 0;
std::string line;
while (std::getline(stream_, line)) {
ParseLine(++line_no, line);
bool ConfigFile::Load(std::istream &istream) {
Json::Value root;
Json::CharReaderBuilder builder;
std::string errorMessage;
if (!Json::parseFromStream(builder, istream, &root, &errorMessage)) {
llvm::errs() << "Failed to parse JSON: " << errorMessage << "\n";
return false;
}
return std::move(cfg_);
}
void ConfigParser::ParseLine(size_t line_no, std::string_view line) {
if (line.empty() || line[0] == ';' || line[0] == '#') {
// Skip empty or comment line.
return;
}
// Parse section name line.
if (line[0] == '[') {
std::string::size_type pos = line.rfind(']');
if (pos == std::string::npos) {
ReportError(line_no, "bad section name line");
return;
for (auto &key : root.getMemberNames()) {
map_[key] = ConfigSection();
if (root[key].isMember("flags")) {
for (auto &flag_keys : root[key]["flags"].getMemberNames()) {
map_[key].map_[flag_keys] = root[key]["flags"][flag_keys].asBool();
}
}
std::string_view section_name = line.substr(1, pos - 1);
section_ = &cfg_.map_[std::string(section_name)];
return;
}
return true;
}
// Parse key-value line.
std::string::size_type pos = line.find('=');
if (pos == std::string::npos) {
ReportError(line_no, "bad key-value line");
return;
}
// Add key-value entry to current section.
std::string_view key = Trim(line.substr(0, pos));
std::string_view value = Trim(line.substr(pos + 1));
if (!section_) {
section_ = &cfg_.map_[""];
}
section_->map_[std::string(key)] = std::string(value);
bool ConfigFile::Load(const std::string &path) {
std::ifstream stream(path);
return Load(stream);
}

View File

@@ -25,12 +25,9 @@ namespace header_checker {
namespace utils {
class ConfigParser;
class ConfigSection {
public:
using MapType = std::map<std::string, std::string>;
using MapType = std::map<std::string, bool>;
using const_iterator = MapType::const_iterator;
@@ -43,15 +40,15 @@ class ConfigSection {
return map_.find(name) != map_.end();
}
std::string GetProperty(const std::string &name) const {
bool GetProperty(const std::string &name) const {
auto &&it = map_.find(name);
if (it == map_.end()) {
return "";
return false;
}
return it->second;
}
std::string operator[](const std::string &name) const {
bool operator[](const std::string &name) const {
return GetProperty(name);
}
@@ -70,9 +67,9 @@ class ConfigSection {
private:
std::map<std::string, std::string> map_;
MapType map_;
friend class ConfigParser;
friend class ConfigFile;
};
@@ -87,6 +84,9 @@ class ConfigFile {
ConfigFile(ConfigFile &&) = default;
ConfigFile &operator=(ConfigFile &&) = default;
bool Load(const std::string &path);
bool Load(std::istream &istream);
bool HasSection(const std::string &section_name) const {
return map_.find(section_name) != map_.end();
}
@@ -110,11 +110,11 @@ class ConfigFile {
return it->second.HasProperty(property_name);
}
std::string GetProperty(const std::string &section_name,
bool GetProperty(const std::string &section_name,
const std::string &property_name) const {
auto &&it = map_.find(section_name);
if (it == map_.end()) {
return "";
return false;
}
return it->second.GetProperty(property_name);
}
@@ -134,55 +134,7 @@ class ConfigFile {
private:
std::map<std::string, ConfigSection> map_;
friend class ConfigParser;
};
class ConfigParser {
public:
using ErrorListener = std::function<void (size_t, const char *)>;
public:
ConfigParser(std::istream &stream)
: stream_(stream), section_(nullptr) { }
ConfigFile ParseFile();
static ConfigFile ParseFile(std::istream &istream);
static ConfigFile ParseFile(const std::string &path);
void SetErrorListener(ErrorListener listener) {
error_listener_ = std::move(listener);
}
private:
void ParseLine(size_t line_no, std::string_view line);
void ReportError(size_t line_no, const char *cause) {
if (error_listener_) {
error_listener_(line_no, cause);
}
}
private:
ConfigParser(const ConfigParser &) = delete;
ConfigParser &operator=(const ConfigParser &) = delete;
private:
std::istream &stream_;
ErrorListener error_listener_;
ConfigSection *section_;
ConfigFile cfg_;
MapType map_;
};

View File

@@ -23,87 +23,66 @@ namespace header_checker {
namespace utils {
TEST(ConfigParserTest, Parse) {
TEST(ConfigFileTest, Parse) {
std::stringstream stream(R"(
# Comment line starts with hash symbol
; Comment line starts with semicolon
[section1]
key1 = value1
key2 = value2
[section2]
key1 = true
key2 = false
// Comment line starts with slash
/* embedded comment */
{
"section1": {
"flags": {
"key1": true,
"key2": false,
},
},
"section2": {
"flags": {
"key1": true,
"key2": false,
},
},
}
)");
auto &&cfg = ConfigParser::ParseFile(stream);
ConfigFile cfg;
cfg.Load(stream);
EXPECT_TRUE(cfg.HasSection("section1"));
EXPECT_TRUE(cfg.HasSection("section2"));
EXPECT_FALSE(cfg.HasSection("section3"));
auto &&section1 = cfg.GetSection("section1");
EXPECT_TRUE(section1.HasProperty("key1"));
EXPECT_EQ("value1", section1.GetProperty("key1"));
EXPECT_TRUE(section1.GetProperty("key1"));
EXPECT_TRUE(section1.HasProperty("key2"));
EXPECT_EQ("value2", section1.GetProperty("key2"));
EXPECT_FALSE(section1.GetProperty("key2"));
EXPECT_FALSE(section1.HasProperty("key3"));
EXPECT_EQ("", section1.GetProperty("key3"));
EXPECT_FALSE(section1.GetProperty("key3"));
auto &&section2 = cfg.GetSection("section2");
EXPECT_TRUE(section2.HasProperty("key1"));
EXPECT_EQ("true", section2.GetProperty("key1"));
EXPECT_TRUE(section2.GetProperty("key1"));
EXPECT_TRUE(section2.HasProperty("key2"));
EXPECT_EQ("false", section2.GetProperty("key2"));
EXPECT_FALSE(section2.GetProperty("key2"));
EXPECT_EQ("value1", cfg.GetProperty("section1", "key1"));
EXPECT_EQ("value2", cfg.GetProperty("section1", "key2"));
EXPECT_TRUE(cfg.GetProperty("section1", "key1"));
EXPECT_FALSE(cfg.GetProperty("section1", "key2"));
EXPECT_EQ("value1", cfg["section1"]["key1"]);
EXPECT_EQ("value2", cfg["section1"]["key2"]);
EXPECT_TRUE(cfg["section1"]["key1"]);
EXPECT_FALSE(cfg["section1"]["key2"]);
}
TEST(ConfigParserTest, BadSectionNameLine) {
TEST(ConfigFileTest, BadJsonFormat) {
std::stringstream stream(R"(
[section1
key1 = value1
)");
size_t num_errors = 0;
ConfigParser parser(stream);
parser.SetErrorListener(
[&num_errors](size_t line_no, const char *cause) {
++num_errors;
EXPECT_EQ(2, line_no);
EXPECT_STREQ("bad section name line", cause);
});
parser.ParseFile();
EXPECT_EQ(1, num_errors);
{
"section1: {
}
}
TEST(ConfigParserTest, BadKeyValueLine) {
std::stringstream stream(R"(
[section1]
key1
)");
size_t num_errors = 0;
ConfigFile cfg;
bool result = cfg.Load(stream);
ConfigParser parser(stream);
parser.SetErrorListener(
[&num_errors](size_t line_no, const char *cause) {
++num_errors;
EXPECT_EQ(3, line_no);
EXPECT_STREQ("bad key-value line", cause);
});
parser.ParseFile();
EXPECT_EQ(1, num_errors);
EXPECT_FALSE(result);
}