10 #include <fmt/format.h>
11 #include <log4cplus/loggingmacros.h>
18 namespace fs = std::filesystem;
21 constexpr
bool AlwaysFalse() {
28 std::optional<KeywordRuleProcessor::DefaultRule>
29 Convert(std::optional<::daq::json::InitialKeywords>
const& rhs) {
30 if (!rhs.has_value()) {
41 throw std::invalid_argument(
42 fmt::format(
"Unknown value of daq::json::InitialKeywords: {}",
43 static_cast<std::underlying_type_t<daq::json::InitialKeywords>
>(*rhs)));
52 JsonReporter(log4cplus::Logger logger) : m_logger(std::move(logger)) {
54 virtual void PostAlert(std::string
const&
id, std::string
const& message)
override {
55 LOG4CPLUS_WARN(m_logger,
"Alert: " << message);
56 Report(
"alert", nlohmann::json({{
"id",
id}, {
"message", message}}));
60 void Report(
char const* type, nlohmann::json
const& content) {
62 std::chrono::nanoseconds(std::chrono::system_clock::now().time_since_epoch()).count();
63 nlohmann::json j{{
"type", type}, {
"timestamp", ts}, {
"content", content}};
66 log4cplus::Logger m_logger;
74 virtual void PostAlert(std::string
const&
id, std::string
const& message)
override {
75 std::cout <<
"[event] alert: " << message <<
'\n';
89 virtual void SortKeywords(std::vector<fits::LiteralKeyword>& keywords)
override {
95 if (!source.is_absolute()) {
104 auto processor = std::make_unique<StandardKeywordRuleProcessor>();
107 [&](
auto const& rule) {
108 using T = std::decay_t<decltype(rule)>;
109 if constexpr (std::is_same_v<T, json::KeywordFilter>) {
110 LOG4CPLUS_DEBUG(
"daq.dpmmerge", fmt::format(
"Adding KeywordRule 'filter'"));
111 processor->AddRule([filter =
KeywordEx(std::begin(rule.selection_patterns),
112 std::end(rule.selection_patterns))](
114 fits::KeywordVector result;
115 result.reserve(kws.size());
116 Filter(std::begin(kws), std::end(kws), std::back_inserter(result), filter);
119 }
else if constexpr (std::is_same_v<T, json::KeywordTransform>) {
120 LOG4CPLUS_DEBUG(
"daq.dpmmerge", fmt::format(
"Adding KeywordRule 'transform'"));
121 processor->AddRule([filter =
KeywordEx(std::begin(rule.selection_patterns),
122 std::end(rule.selection_patterns)),
123 regex = std::regex(rule.regex),
124 format = rule.format](
126 fits::KeywordVector result;
127 result.reserve(kws.size());
128 Transform(std::begin(kws),
130 std::back_inserter(result),
137 static_assert(AlwaysFalse<T>(),
"non exhaustive visitor");
146 std::optional<fs::path>
const& opt_out_path,
154 auto out_path = opt_out_path.value_or(
159 LOG4CPLUS_INFO(
"daq.dpmmerge",
160 fmt::format(
"*in-place* target specified act as merge target: '{}'",
165 resolver.
Resolve({spec.target.source->source_name, spec.target.source->location}),
178 std::move(kw_rules));
182 LOG4CPLUS_INFO(
"daq.dpmmerge",
183 "no *in-place* target specified -> creating minimal FITS file to "
184 "act as merge target");
188 std::optional<KeywordRuleProcessor::DefaultRule> initial_keywords = std::nullopt;
194 std::make_unique<StandardKeywordRuleProcessor>(),
195 std::move(dry_run_file).GetOwnedFile());
202 std::make_unique<StandardKeywordRuleProcessor>());
207 std::vector<SourceTypes> sources;
210 [&](
auto const& source) {
211 using T = std::decay_t<decltype(source)>;
214 if constexpr (std::is_same_v<T, json::FitsKeywordsSource>) {
215 sources.emplace_back(std::in_place_type<FitsKeywordsSource>,
218 Convert(source.initial_keywords),
219 std::move(kw_rules));
220 }
else if constexpr (std::is_same_v<T, json::FitsFileSource>) {
222 resolver.
Resolve({source.source_name, source.location}), root);
223 sources.emplace_back(std::in_place_type<FitsFileSource>,
227 Convert(source.initial_keywords),
228 std::move(kw_rules));
230 static_assert(AlwaysFalse<T>(),
"non exhaustive visitor");
237 auto logger = log4cplus::Logger::getInstance(
"daq.dpmmerge");
250 params.
origfile = out_path.filename().native();
253 Merge(ops, params, target_source, sources, dry_run);
255 std::throw_with_nested(std::runtime_error(
"Merge failed"));
259 target_source.Close();
262 fs::permissions(target_source.GetFilePath(),
263 fs::perms::owner_read | fs::perms::group_read | fs::perms::others_read,
264 fs::perm_options::replace);
265 fs::rename(target_source.GetFilePath(), out_path);
Contains functions and data structures related to cfitsio.
Create keyword expression that memoize the provided string pattern.
@ None
None (to disable keyword copying)
@ User
Default is to keep only user-keywords.
@ All
Default rule is to keep all keywords (useful for in-place merge)
Provides location of fits source file.
auto Resolve(SourceFile const &source) const -> std::filesystem::path
Resolves local file that was previously added with Add().
virtual void PostAlert(std::string const &id, std::string const &message) override
Post event.
JsonReporter(log4cplus::Logger logger)
Reports in unspecified human-readable format.
virtual void PostAlert(std::string const &id, std::string const &message) override
Post event.
virtual void SortKeywords(std::vector< fits::LiteralKeyword > &keywords) override
Sort keywords.
Interface to reporter (implementations exist for JSON or human readable)
Represents the literal 80-character FITS keyword record.
std::optional< KeywordRuleProcessor::DefaultRule > Convert(std::optional<::daq::json::InitialKeywords > const &rhs)
int Entrypoint(fs::path const &root, std::optional< fs::path > const &opt_out_path, json::DpSpec const &spec, SourceResolver const &resolver, bool dry_run, bool use_json)
void Merge(Operations ops, Params const ¶ms, TargetSource &target, std::vector< SourceTypes > const &sources, bool dry_run)
Merge sources into the target target.
fs::path MakeSourcePath(fs::path source, fs::path const &root)
std::unique_ptr< KeywordRuleProcessor > MakeKeywordRuleProcessor(json::KeywordRules const &rules)
void StandardSort(std::vector< LiteralKeyword > &keywords)
Sorts keywords according to ESO DICD standards.
UniqueFitsFile Open(char const *filename, OpenMode mode)
Open file.
LiteralKeyword Format(KeywordVariant const &keyword)
void InitPrimaryHduNoImage(fitsfile *ptr)
Initializes an empty FITS file with a primary HDU.
std::vector< KeywordVariant > KeywordVector
Vector of keywords.
std::variant< ValueKeyword, EsoKeyword, LiteralKeyword > KeywordVariant
The different variants of keywords that are supported.
UniqueFitsFile CreateEmpty(char const *filename)
Creates empty FITS file using fits_create_file and returns a pointer with a deleter that will close t...
@ None
Keeps nothing (useful for disabling keyword copying)
@ User
Keep only user-keywords.
@ All
Keep all keywords (useful for in-place merge)
std::optional< FitsFileSource > source
std::vector< KeywordRuleTypes > KeywordRules
std::vector< SourceTypes > sources
std::variant< FitsKeywordsSource, FitsFileSource > SourceTypes
std::string file_prefix
Optioal user chosen file prefix to make it easier to identify the produced file.
std::variant< KeywordFilter, KeywordTransform > KeywordRuleTypes
Close representation of the JSON structure but with stronger types.