/Users/deen/code/yugabyte-db/src/yb/util/version_info.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include "yb/util/version_info.h" |
34 | | |
35 | | #include <fstream> |
36 | | #include <string> |
37 | | |
38 | | #include <rapidjson/document.h> |
39 | | #include <rapidjson/error/en.h> |
40 | | #include <rapidjson/istreamwrapper.h> |
41 | | #include <rapidjson/writer.h> |
42 | | |
43 | | #include "yb/util/env_util.h" |
44 | | #include "yb/util/path_util.h" |
45 | | #include "yb/util/status.h" |
46 | | #include "yb/util/status_log.h" |
47 | | |
48 | | DEFINE_string(version_file_json_path, "", |
49 | | "Path to directory containing JSON file with version info."); |
50 | | |
51 | | using std::string; |
52 | | |
53 | | namespace yb { |
54 | | |
55 | | const char* kVersionJsonFileName = "version_metadata.json"; |
56 | | |
57 | | std::once_flag VersionInfo::init_once_; |
58 | | std::shared_ptr<const VersionData> VersionInfo::version_data_ = nullptr; |
59 | | |
60 | 0 | string VersionInfo::GetGitHash() { |
61 | 0 | auto data = GetVersionData(); |
62 | |
|
63 | 0 | string ret = data->pb.git_hash(); |
64 | 0 | if (!data->pb.build_clean_repo()) { |
65 | 0 | ret += "-dirty"; |
66 | 0 | } |
67 | 0 | return ret; |
68 | 0 | } |
69 | | |
70 | 1.02M | string VersionInfo::GetShortVersionString() { |
71 | 1.02M | auto data = GetVersionData(); |
72 | | |
73 | 1.02M | return strings::Substitute("version $0 build $1 revision $2 build_type $3 built at $4", |
74 | 1.02M | data->pb.version_number(), |
75 | 1.02M | data->pb.build_number(), |
76 | 1.02M | data->pb.git_hash(), |
77 | 1.02M | data->pb.build_type(), |
78 | 1.02M | data->pb.build_timestamp()); |
79 | 1.02M | } |
80 | | |
81 | 0 | string VersionInfo::GetAllVersionInfo() { |
82 | 0 | auto data = GetVersionData(); |
83 | |
|
84 | 0 | string ret = strings::Substitute( |
85 | 0 | "version $0\n" |
86 | 0 | "build $1\n" |
87 | 0 | "revision $2\n" |
88 | 0 | "build_type $3\n" |
89 | 0 | "built by $4 at $5 on $6", |
90 | 0 | data->pb.version_number(), |
91 | 0 | data->pb.build_number(), |
92 | 0 | GetGitHash(), |
93 | 0 | data->pb.build_type(), |
94 | 0 | data->pb.build_username(), |
95 | 0 | data->pb.build_timestamp(), |
96 | 0 | data->pb.build_hostname()); |
97 | 0 | if (data->pb.build_id().size() > 0) { |
98 | 0 | strings::SubstituteAndAppend(&ret, "\nbuild id $0", data->pb.build_id()); |
99 | 0 | } |
100 | | #ifdef ADDRESS_SANITIZER |
101 | | ret += "\nASAN enabled"; |
102 | | #endif |
103 | | #ifdef THREAD_SANITIZER |
104 | | ret += "\nTSAN enabled"; |
105 | | #endif |
106 | 0 | return ret; |
107 | 0 | } |
108 | | |
109 | 4 | string VersionInfo::GetAllVersionInfoJson() { |
110 | 4 | return std::atomic_load_explicit(&version_data_, std::memory_order_acquire)->json; |
111 | 4 | } |
112 | | |
113 | 2.54k | void VersionInfo::GetVersionInfoPB(VersionInfoPB* pb) { |
114 | 2.54k | pb->CopyFrom(GetVersionData()->pb); |
115 | 2.54k | } |
116 | | |
117 | 11.6k | Status VersionInfo::ReadVersionDataFromFile() { |
118 | 11.6k | SCHECK(std::atomic_load_explicit(&version_data_, std::memory_order_acquire) == nullptr, |
119 | 11.6k | IllegalState, "Cannot reload version data from file..."); |
120 | | |
121 | 11.6k | std::string version_file_path = FLAGS_version_file_json_path; |
122 | 11.6k | if (version_file_path.empty()) { |
123 | 11.6k | version_file_path = yb::env_util::GetRootDir("bin"); |
124 | 11.6k | } |
125 | | |
126 | 11.6k | std::string config_file_path = JoinPathSegments(version_file_path, kVersionJsonFileName); |
127 | 11.6k | std::ifstream json_file(config_file_path); |
128 | 11.6k | SCHECK(!json_file.fail(), |
129 | 11.6k | IllegalState, strings::Substitute("Could not open JSON file $0", config_file_path)); |
130 | | |
131 | 11.6k | rapidjson::IStreamWrapper isw(json_file); |
132 | 11.6k | rapidjson::Document d; |
133 | 11.6k | d.ParseStream(isw); |
134 | 11.6k | SCHECK(!d.HasParseError(), |
135 | 11.6k | IllegalState, strings::Substitute("Failed to parse json. Error: $0 ", |
136 | 11.6k | rapidjson::GetParseError_En(d.GetParseError()))); |
137 | | |
138 | 11.6k | auto version_data = std::make_shared<VersionData>(); |
139 | | |
140 | 11.6k | rapidjson::StringBuffer buffer; |
141 | 11.6k | rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); |
142 | 11.6k | d.Accept(writer); |
143 | | |
144 | 11.6k | version_data->json = buffer.GetString(); |
145 | | |
146 | 11.6k | const std::map<std::string, std::string*> keys_and_outputs = { |
147 | 11.6k | { "git_hash", version_data->pb.mutable_git_hash() }, |
148 | 11.6k | { "build_hostname", version_data->pb.mutable_build_hostname() }, |
149 | 11.6k | { "build_timestamp", version_data->pb.mutable_build_timestamp() }, |
150 | 11.6k | { "build_username", version_data->pb.mutable_build_username() }, |
151 | 11.6k | { "build_id", version_data->pb.mutable_build_id() }, |
152 | 11.6k | { "build_type", version_data->pb.mutable_build_type() }, |
153 | 11.6k | { "version_number", version_data->pb.mutable_version_number() }, |
154 | 11.6k | { "build_number", version_data->pb.mutable_build_number() } |
155 | 11.6k | }; |
156 | | |
157 | 93.3k | for (const auto& entry : keys_and_outputs) { |
158 | 93.3k | const auto& key = entry.first; |
159 | 93.3k | auto* output = entry.second; |
160 | 93.3k | if (!d.HasMember(key.c_str())) { |
161 | 0 | return STATUS(IllegalState, strings::Substitute("Key $0 does not exist", key)); |
162 | 93.3k | } else if(!d[key.c_str()].IsString()) { |
163 | 0 | return STATUS(IllegalState, strings::Substitute("Key $0 is of invalid type $1", |
164 | 0 | key, d[key.c_str()].GetType())); |
165 | 0 | } |
166 | 93.3k | *output = d[key.c_str()].GetString(); |
167 | 93.3k | } |
168 | | |
169 | | // Special case the only boolean flag... |
170 | 11.6k | if (!d.HasMember("build_clean_repo")) { |
171 | 0 | return STATUS(IllegalState, strings::Substitute("Key $0 does not exist", "build_clean_repo")); |
172 | 11.6k | } else if(!d["build_clean_repo"].IsString()) { |
173 | 0 | return STATUS(IllegalState, |
174 | 0 | strings::Substitute("Key $0 is of invalid type $1", |
175 | 0 | "build_clean_repo", d["build_clean_repo"].GetType())); |
176 | 11.6k | } else { |
177 | 11.6k | version_data->pb.set_build_clean_repo(d["build_clean_repo"] == "true"); |
178 | 11.6k | } |
179 | | |
180 | 11.6k | std::atomic_store_explicit(&version_data_, |
181 | 11.6k | static_cast<std::shared_ptr<const VersionData>>(version_data), |
182 | 11.6k | std::memory_order_release); |
183 | 11.6k | return Status::OK(); |
184 | 11.6k | } |
185 | | |
186 | 1.04M | Status VersionInfo::Init() { |
187 | 1.04M | Status status; |
188 | 1.04M | std::call_once(init_once_, InitInternal, &status); |
189 | 1.04M | return status; |
190 | 1.04M | } |
191 | | |
192 | 1.03M | std::shared_ptr<const VersionData> VersionInfo::GetVersionData() { |
193 | 1.03M | CHECK_OK(Init()); |
194 | 1.03M | return std::atomic_load_explicit(&version_data_, std::memory_order_acquire); |
195 | 1.03M | } |
196 | | |
197 | 11.6k | void VersionInfo::InitInternal(Status* status_dest) { |
198 | 11.6k | *status_dest = ReadVersionDataFromFile(); |
199 | 11.6k | } |
200 | | |
201 | | } // namespace yb |