• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/config/fetcher_config.h"
18 
19 #include <fstream>
20 #include <map>
21 #include <string>
22 #include <vector>
23 
24 #include "android-base/logging.h"
25 #include "android-base/strings.h"
26 #include "gflags/gflags.h"
27 #include "json/json.h"
28 
29 #include "common/libs/utils/files.h"
30 
31 namespace cuttlefish {
32 
33 namespace {
34 
35 const char* kFlags = "flags";
36 const char* kCvdFiles = "cvd_files";
37 const char* kCvdFileSource = "source";
38 const char* kCvdFileBuildId = "build_id";
39 const char* kCvdFileBuildTarget = "build_target";
40 
SourceStringToEnum(std::string source)41 FileSource SourceStringToEnum(std::string source) {
42   for (auto& c : source) {
43     c = std::tolower(c);
44   }
45   if (source == "default_build") {
46     return FileSource::DEFAULT_BUILD;
47   } else if (source == "system_build") {
48     return FileSource::SYSTEM_BUILD;
49   } else if (source == "kernel_build") {
50     return FileSource::KERNEL_BUILD;
51   } else if (source == "local_file") {
52     return FileSource::LOCAL_FILE;
53   } else if (source == "generated") {
54     return FileSource::GENERATED;
55   } else if (source == "bootloader_build") {
56     return FileSource::BOOTLOADER_BUILD;
57   } else if (source == "boot_build") {
58     return FileSource::BOOT_BUILD;
59   } else if (source == "host_package_build") {
60     return FileSource::HOST_PACKAGE_BUILD;
61   } else {
62     return FileSource::UNKNOWN_PURPOSE;
63   }
64 }
65 
SourceEnumToString(const FileSource & source)66 std::string SourceEnumToString(const FileSource& source) {
67   if (source == FileSource::DEFAULT_BUILD) {
68     return "default_build";
69   } else if (source == FileSource::SYSTEM_BUILD) {
70     return "system_build";
71   } else if (source == FileSource::KERNEL_BUILD) {
72     return "kernel_build";
73   } else if (source == FileSource::LOCAL_FILE) {
74     return "local_file";
75   } else if (source == FileSource::GENERATED) {
76     return "generated";
77   } else if (source == FileSource::BOOTLOADER_BUILD) {
78     return "bootloader_build";
79   } else if (source == FileSource::BOOT_BUILD) {
80     return "boot_build";
81   } else if (source == FileSource::HOST_PACKAGE_BUILD) {
82     return "host_package_build";
83   } else {
84     return "unknown";
85   }
86 }
87 
88 } // namespace
89 
CvdFile()90 CvdFile::CvdFile() {
91 }
92 
CvdFile(const FileSource & source,const std::string & build_id,const std::string & build_target,const std::string & file_path)93 CvdFile::CvdFile(const FileSource& source, const std::string& build_id,
94                  const std::string& build_target, const std::string& file_path)
95     : source(source), build_id(build_id), build_target(build_target), file_path(file_path) {
96 }
97 
operator <<(std::ostream & os,const CvdFile & cvd_file)98 std::ostream& operator<<(std::ostream& os, const CvdFile& cvd_file) {
99   os << "CvdFile(";
100   os << "source = " << SourceEnumToString(cvd_file.source) << ", ";
101   os << "build_id = " << cvd_file.build_id << ", ";
102   os << "build_target = " << cvd_file.build_target << ", ";
103   os << "file_path = " << cvd_file.file_path << ")";
104   return os;
105 }
106 
FetcherConfig()107 FetcherConfig::FetcherConfig() : dictionary_(new Json::Value()) {
108 }
109 
110 FetcherConfig::FetcherConfig(FetcherConfig&&) = default;
111 
~FetcherConfig()112 FetcherConfig::~FetcherConfig() {
113 }
114 
SaveToFile(const std::string & file) const115 bool FetcherConfig::SaveToFile(const std::string& file) const {
116   std::ofstream ofs(file);
117   if (!ofs.is_open()) {
118     LOG(ERROR) << "Unable to write to file " << file;
119     return false;
120   }
121   ofs << *dictionary_;
122   return !ofs.fail();
123 }
124 
LoadFromFile(const std::string & file)125 bool FetcherConfig::LoadFromFile(const std::string& file) {
126   auto real_file_path = AbsolutePath(file);
127   if (real_file_path.empty()) {
128     LOG(ERROR) << "Could not get real path for file " << file;
129     return false;
130   }
131   Json::CharReaderBuilder builder;
132   std::ifstream ifs(real_file_path);
133   std::string errorMessage;
134   if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
135     LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage;
136     return false;
137   }
138   return true;
139 }
140 
RecordFlags()141 void FetcherConfig::RecordFlags() {
142   std::vector<gflags::CommandLineFlagInfo> all_flags;
143   GetAllFlags(&all_flags);
144   Json::Value flags_json(Json::arrayValue);
145   for (const auto& flag : all_flags) {
146     Json::Value flag_json;
147     flag_json["name"] = flag.name;
148     flag_json["type"] = flag.type;
149     flag_json["description"] = flag.description;
150     flag_json["current_value"] = flag.current_value;
151     flag_json["default_value"] = flag.default_value;
152     flag_json["filename"] = flag.filename;
153     flag_json["has_validator_fn"] = flag.has_validator_fn;
154     flag_json["is_default"] = flag.is_default;
155     flags_json.append(flag_json);
156   }
157   (*dictionary_)[kFlags] = flags_json;
158 }
159 
160 namespace {
161 
JsonToCvdFile(const std::string & file_path,const Json::Value & json)162 CvdFile JsonToCvdFile(const std::string& file_path, const Json::Value& json) {
163   CvdFile cvd_file;
164   cvd_file.file_path = file_path;
165   if (json.isMember(kCvdFileSource)) {
166     cvd_file.source = SourceStringToEnum(json[kCvdFileSource].asString());
167   } else {
168     cvd_file.source = UNKNOWN_PURPOSE;
169   }
170   if (json.isMember(kCvdFileBuildId)) {
171     cvd_file.build_id = json[kCvdFileBuildId].asString();
172   }
173   if (json.isMember(kCvdFileBuildTarget)) {
174     cvd_file.build_target = json[kCvdFileBuildTarget].asString();
175   }
176   return cvd_file;
177 }
178 
CvdFileToJson(const CvdFile & cvd_file)179 Json::Value CvdFileToJson(const CvdFile& cvd_file) {
180   Json::Value json;
181   json[kCvdFileSource] = SourceEnumToString(cvd_file.source);
182   json[kCvdFileBuildId] = cvd_file.build_id;
183   json[kCvdFileBuildTarget] = cvd_file.build_target;
184   return json;
185 }
186 
187 } // namespace
188 
add_cvd_file(const CvdFile & file,bool override_entry)189 bool FetcherConfig::add_cvd_file(const CvdFile& file, bool override_entry) {
190   if (!dictionary_->isMember(kCvdFiles)) {
191     Json::Value files_json(Json::objectValue);
192     (*dictionary_)[kCvdFiles] = files_json;
193   }
194   if ((*dictionary_)[kCvdFiles].isMember(file.file_path) && !override_entry) {
195     return false;
196   }
197   (*dictionary_)[kCvdFiles][file.file_path] = CvdFileToJson(file);
198   return true;
199 }
200 
get_cvd_files() const201 std::map<std::string, CvdFile> FetcherConfig::get_cvd_files() const {
202   if (!dictionary_->isMember(kCvdFiles)) {
203     return {};
204   }
205   std::map<std::string, CvdFile> files;
206   const auto& json_files = (*dictionary_)[kCvdFiles];
207   for (auto it = json_files.begin(); it != json_files.end(); it++) {
208     files[it.key().asString()] = JsonToCvdFile(it.key().asString(), *it);
209   }
210   return files;
211 }
212 
FindCvdFileWithSuffix(const std::string & suffix) const213 std::string FetcherConfig::FindCvdFileWithSuffix(const std::string& suffix) const {
214   if (!dictionary_->isMember(kCvdFiles)) {
215     return {};
216   }
217   const auto& json_files = (*dictionary_)[kCvdFiles];
218   for (auto it = json_files.begin(); it != json_files.end(); it++) {
219     const auto& file = it.key().asString();
220     if (android::base::EndsWith(file, suffix)) {
221       return file;
222     }
223   }
224   LOG(DEBUG) << "Could not find file ending in " << suffix;
225   return "";
226 }
227 
228 } // namespace cuttlefish
229