| // Copyright 2020 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "components/fuchsia_component_support/config_reader.h" | |
| #include <string> | |
| #include <utility> | |
| #include "base/check.h" | |
| #include "base/files/file_enumerator.h" | |
| #include "base/files/file_path.h" | |
| #include "base/files/file_util.h" | |
| #include "base/json/json_reader.h" | |
| #include "base/logging.h" | |
| #include "base/no_destructor.h" | |
| namespace fuchsia_component_support { | |
| namespace { | |
| bool HaveConflicts(const base::DictValue& dict1, const base::DictValue& dict2) { | |
| for (auto item : dict1) { | |
| const base::Value* value = dict2.Find(item.first); | |
| if (!value) | |
| continue; | |
| if (!value->is_dict()) | |
| return true; | |
| if (HaveConflicts(item.second.GetDict(), value->GetDict())) | |
| return true; | |
| } | |
| return false; | |
| } | |
| base::DictValue ReadConfigFile(const base::FilePath& path) { | |
| std::string file_content; | |
| bool loaded = base::ReadFileToString(path, &file_content); | |
| CHECK(loaded) << "Couldn't read config file: " << path; | |
| auto parsed = base::JSONReader::ReadAndReturnValueWithError( | |
| file_content, base::JSON_PARSE_CHROMIUM_EXTENSIONS); | |
| CHECK(parsed.has_value()) | |
| << "Failed to parse " << path << ": " << parsed.error().message; | |
| CHECK(parsed->is_dict()) << "Config is not a JSON dictionary: " << path; | |
| return std::move(parsed->GetDict()); | |
| } | |
| std::optional<base::DictValue> ReadConfigsFromDir(const base::FilePath& dir) { | |
| base::FileEnumerator configs(dir, false, base::FileEnumerator::FILES, | |
| "*.json"); | |
| std::optional<base::DictValue> config; | |
| for (base::FilePath path; !(path = configs.Next()).empty();) { | |
| base::DictValue path_config = ReadConfigFile(path); | |
| if (config) { | |
| CHECK(!HaveConflicts(*config, path_config)); | |
| config->Merge(std::move(path_config)); | |
| } else { | |
| config = std::move(path_config); | |
| } | |
| } | |
| return config; | |
| } | |
| } // namespace | |
| const std::optional<base::DictValue>& LoadPackageConfig() { | |
| // Package configurations do not change at run-time, so read the configuration | |
| // on the first call and cache the result. | |
| static base::NoDestructor<std::optional<base::DictValue>> config( | |
| ReadConfigsFromDir(base::FilePath("/config/data"))); | |
| return *config; | |
| } | |
| std::optional<base::DictValue> LoadConfigFromDirForTest( // IN-TEST | |
| const base::FilePath& dir) { | |
| return ReadConfigsFromDir(dir); | |
| } | |
| } // namespace fuchsia_component_support |