8 #include <fmt/format.h>
18 template <
class... Args>
21 (fmt::format(
"({}) {}", ptr.to_string(), fmt::format(std::forward<Args>(args)...)))
25 template <
char const*>
27 return DpSpecError(fmt::format(
"({}) {}", ptr.to_string(), str).c_str());
31 return DpSpecError(fmt::format(
"({}) {}", ptr.to_string(),
"mandatory value missing").c_str());
37 fmt::format(
"({}) {}",
39 fmt::format(
"must be a {}, but is {}", expected_type, actual_type))
44 char const* known_variants,
45 char const* actual_variant) {
47 fmt::format(
"({}) {}",
49 fmt::format(
"must be one of {}, but is '{}'", known_variants, actual_variant))
57 bool allow_empty =
true);
60 std::string GetMember<std::string>(
Json const&
json,
64 if (!
json.contains(name)) {
67 auto const& value_json =
json[name];
68 if (!value_json.is_string()) {
71 auto value = value_json.get<std::string>();
72 if (value.empty() && !allow_empty) {
79 if (!
json.is_object()) {
85 if (!
json.is_array()) {
92 std::vector<std::string> result;
94 for (
auto const& value_json :
json) {
95 if (!value_json.is_string()) {
98 auto value = value_json.get<std::string>();
102 result.emplace_back(std::move(value));
110 if (!
json.contains(
"selectionPatterns")) {
121 if (!
json.contains(
"selectionPatterns")) {
127 transform.
regex = GetMember<std::string>(
json,
"regex", breadcrumb);
128 transform.
format = GetMember<std::string>(
json,
"format", breadcrumb);
136 for (
auto const& json_element :
json) {
137 auto type = GetMember<std::string>(json_element,
"type", breadcrumb);
138 if (type ==
"filter") {
139 result.emplace_back(
ParseFilter(json_element, breadcrumb));
140 }
else if (type ==
"transform") {
144 breadcrumb /
"type",
"'filter' or 'transform'", type.c_str());
151 DpSpec::SourceFitsKeywords
155 obj.
source_name = GetMember<std::string>(
json,
"sourceName", breadcrumb);
157 if (
json.contains(
"keywordRules")) {
160 if (!
json.contains(
"keywords")) {
167 }
catch (std::exception
const& err) {
168 std::throw_with_nested(
176 obj.
source_name = GetMember<std::string>(
json,
"sourceName", breadcrumb);
177 obj.
origin = GetMember<std::string>(
json,
"origin", breadcrumb);
179 if (
json.contains(
"keywordRules")) {
188 obj.
file_id = GetMember<std::string>(
json,
"fileId", breadcrumb);
189 if (
json.contains(
"source")) {
192 if (
json.contains(
"filePrefix")) {
193 obj.file_prefix = GetMember<std::string>(
json,
"filePrefix", breadcrumb,
true);
200 auto type = GetMember<std::string>(
json,
"type", breadcrumb);
201 if (type ==
"fitsKeywords") {
203 }
else if (type ==
"fitsFile") {
207 breadcrumb /
"type",
"'fitsKeywords' or 'fitsFile'", type.c_str());
217 spec.
id = GetMember<std::string>(
json,
"id", breadcrumb);
218 if (!
json.contains(
"target")) {
223 if (
json.contains(
"sources")) {
224 auto const& json_sources =
json[
"sources"];
225 if (!json_sources.is_array()) {
227 breadcrumb /
"sources",
"array", json_sources.type_name());
231 for (
auto const& json_source : json_sources) {
232 spec.sources.emplace_back(
ParseSource(json_source, breadcrumb /
"sources" / index));
237 if (!spec.target.source && spec.sources.empty()) {
239 breadcrumb /
"sources",
240 "At least one source must be provided if '/target/source' is not used");
246 std::throw_with_nested(
DpSpecError(
"Unknown parsing error"));
254 auto start_pos = origin_str.find(
'@');
255 if (start_pos == std::string::npos) {
259 if (start_pos > origin_str.size()) {
260 throw std::invalid_argument(
261 fmt::format(
"Invalid format of origin string: '{}'", origin_str));
267 auto pos = origin_str.find(
':', start_pos);
268 if (pos != std::string::npos) {
270 origin.
host = origin_str.substr(start_pos, pos - start_pos);
271 origin.
path = origin_str.substr(pos + 1, std::string::npos);
273 origin.
path = origin_str.substr(start_pos);
275 if (origin.
path.empty()) {
276 throw std::invalid_argument(
277 fmt::format(
"Invalid format of origin string: '{}'", origin_str));
286 return (
host + std::string(
":") +
path.native());