1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/fuchsia_component_support/config_reader.h"
10 #include "base/check.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_reader.h"
15 #include "base/logging.h"
16 #include "base/no_destructor.h"
18 namespace fuchsia_component_support {
22 bool HaveConflicts(const base::Value::Dict& dict1,
23 const base::Value::Dict& dict2) {
24 for (auto item : dict1) {
25 const base::Value* value = dict2.Find(item.first);
28 if (!value->is_dict())
30 if (HaveConflicts(item.second.GetDict(), value->GetDict()))
37 base::Value::Dict ReadConfigFile(const base::FilePath& path) {
38 std::string file_content;
39 bool loaded = base::ReadFileToString(path, &file_content);
40 CHECK(loaded) << "Couldn't read config file: " << path;
42 auto parsed = base::JSONReader::ReadAndReturnValueWithError(file_content);
43 CHECK(parsed.has_value())
44 << "Failed to parse " << path << ": " << parsed.error().message;
45 CHECK(parsed->is_dict()) << "Config is not a JSON dictionary: " << path;
47 return std::move(parsed->GetDict());
50 absl::optional<base::Value::Dict> ReadConfigsFromDir(
51 const base::FilePath& dir) {
52 base::FileEnumerator configs(dir, false, base::FileEnumerator::FILES,
54 absl::optional<base::Value::Dict> config;
55 for (base::FilePath path; !(path = configs.Next()).empty();) {
56 base::Value::Dict path_config = ReadConfigFile(path);
58 CHECK(!HaveConflicts(*config, path_config));
59 config->Merge(std::move(path_config));
61 config = std::move(path_config);
70 const absl::optional<base::Value::Dict>& LoadPackageConfig() {
71 // Package configurations do not change at run-time, so read the configuration
72 // on the first call and cache the result.
73 static base::NoDestructor<absl::optional<base::Value::Dict>> config(
74 ReadConfigsFromDir(base::FilePath("/config/data")));
79 absl::optional<base::Value::Dict> LoadConfigFromDirForTest( // IN-TEST
80 const base::FilePath& dir) {
81 return ReadConfigsFromDir(dir);
84 } // namespace fuchsia_component_support