10 #include <boost/program_options.hpp>
11 #include <fmt/format.h>
12 #include <log4cplus/configurator.h>
13 #include <log4cplus/logger.h>
14 #include <log4cplus/loggingmacros.h>
15 #include <nlohmann/json.hpp>
61 std::pair<std::string, std::string>
CustomParser(std::string
const& element) {
63 return std::make_pair(
"specification-file",
"-");
68 int main(
int argc,
char** argv) {
69 log4cplus::initialize();
71 log4cplus::BasicConfigurator config(log4cplus::Logger::getDefaultHierarchy(),
true);
74 namespace po = boost::program_options;
76 auto logger = log4cplus::Logger::getInstance(
"daq.dpmmerge");
78 const std::string synopsis(
"daqDpmMerge [options] <specification-file>");
80 po::positional_options_description positional;
81 positional.add(
"specification-file", 1);
83 std::string spec_file;
84 po::options_description options(synopsis);
88 "produce help message (also use this option for each command to get relevant help)")
92 po::value<std::string>(),
93 "specifies root directory from which relative source file paths in specification-file will"
94 " be resolved as well as the default output directory. If not specified it will use the "
95 "root of the specification-file file or if "
96 "specification-file is not a regular file it will use current working directory.")
98 po::value<std::string>(),
99 "FITS output file name, e.g. `-o myfits.fits`. By default the output name will be "
100 "derived using the specification-file `fileId` property: `<fileId>.fits`. "
101 "Relative paths are relative the root directory.")
103 po::value<std::string>(),
104 "specifies optional FITS source resolver which resolves location of input FITS files "
105 "to their location on this host. If specification references FITS files this must be "
108 "output status messages to standard out in JSON format")
110 "skips operations with visible side-effects, useful for validating inputs")
112 po::options_description hidden(
"Hidden options");
114 (
"specification-file", po::value<std::string>(&spec_file),
"input file")
118 po::options_description all(
"All");
119 all.add(options).add(hidden);
121 po::variables_map vm;
123 auto parsed = po::command_line_parser(argc, argv)
125 .positional(positional)
128 po::store(parsed, vm);
129 if (vm.count(
"help")) {
130 std::cerr << options << std::endl;
133 if (vm.count(
"version")) {
134 std::cerr <<
"daqDpmMerge " << VERSION
144 if (!vm.count(
"specification-file")) {
145 std::cerr <<
"argument error: specification-file not provided" << std::endl;
148 spec_file = vm[
"specification-file"].as<std::string>();
152 auto root_arg = vm.count(
"root") ? vm[
"root"].as<std::string>() : std::string();
153 auto root_path = std::filesystem::path();
154 if (!root_arg.empty()) {
157 std::filesystem::path(root_arg, std::filesystem::path::format::native_format);
158 if (!std::filesystem::is_directory(root_path)) {
159 std::cerr <<
"argument error: --root argument \"" << root_arg
160 <<
"\" is not a valid directory" << std::endl;
163 }
else if (std::filesystem::is_regular_file(spec_file)) {
165 root_path = std::filesystem::path(spec_file).parent_path();
168 root_path = std::filesystem::current_path();
172 std::optional<std::filesystem::path> out_path;
173 if (vm.count(
"outfile")) {
174 auto out = std::filesystem::path(vm[
"outfile"].as<std::string>());
175 if (out.is_relative()) {
176 out = root_path / out;
178 if (std::filesystem::exists(out)) {
179 std::cerr <<
"argument error: --outfile argument " << out <<
" exists" << std::endl;
187 if (vm.count(
"resolver")) {
188 auto resolver_path = std::filesystem::path(vm[
"resolver"].as<std::string>());
189 if (resolver_path.is_relative()) {
190 resolver_path = root_path / resolver_path;
192 if (!std::filesystem::exists(resolver_path)) {
193 std::cerr <<
"argument error: --resolver argument " << resolver_path <<
" not found"
197 std::ifstream file(resolver_path);
199 std::cerr <<
"error: failed to open specification with path '" << resolver_path
203 auto json = nlohmann::json::parse(file);
208 nlohmann::json json_spec;
209 if (spec_file ==
"-") {
211 json_spec = nlohmann::json::parse(std::cin);
214 std::ifstream file(spec_file);
216 std::cerr <<
"error: failed to open specification with path '" << spec_file
220 json_spec = nlohmann::json::parse(file);
223 auto use_json = vm.count(
"json");
224 auto dry_run = vm.count(
"dry-run");
230 root_path, out_path, dp_spec, resolver, dry_run, use_json);
237 fmt::format(
"Failed to parse Data Product Specification '{}'", spec_file)));
242 }
catch (po::error
const& e) {
245 }
catch (nlohmann::json::parse_error
const& e) {
246 std::cerr <<
"error: json parsing failed: " << e.what() << std::endl;
248 }
catch (nlohmann::json::exception
const& e) {
249 std::cerr <<
"error: json error: " << e.what() << std::endl;
254 }
catch (std::exception
const& e) {
Provides location of fits source file.
void SetMapping(Mapping mapping) noexcept
std::map< SourceFile, std::string > Mapping
int main(int argc, char **argv)
std::pair< std::string, std::string > CustomParser(std::string const &element)
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 ReportNestedExceptions(std::ostream &os) noexcept
DpSpec ParseDpSpec(Json const &json)
Parse JSON to construct the DpSpec structure.
@ InvalidProgramArgument
Invalid program arguments.
@ DpSpecNotFound
Data product specification file not found.
@ DpSpecInvalid
Invalid Data Product Specification.
@ DpSpecInvalidJson
Invalid Data Product Specification JSON
ExitWithErrorCode(int code)