Newer
Older
#include <glog/logging.h>
#include <ftl/config.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include <nlohmann/json.hpp>
#include <ftl/configuration.hpp>
#include <fstream>
#include <string>
#include <map>
#include <iostream>
using nlohmann::json;
using std::ifstream;
using std::string;
using std::map;
using std::vector;
using std::optional;
using ftl::is_file;
using ftl::is_directory;
// Store loaded configuration
namespace ftl {
json config;
};
using ftl::config;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
bool ftl::is_directory(const std::string &path) {
#ifdef WIN32
DWORD attrib = GetFileAttributesA(path.c_str());
if (attrib == INVALID_FILE_ATTRIBUTES) return false;
else return (attrib & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat s;
if (::stat(path.c_str(), &s) == 0) {
return S_ISDIR(s.st_mode);
} else {
return false;
}
#endif
}
bool ftl::is_file(const std::string &path) {
#ifdef WIN32
DWORD attrib = GetFileAttributesA(path.c_str());
if (attrib == INVALID_FILE_ATTRIBUTES) return false;
else return !(attrib & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat s;
if (::stat(path.c_str(), &s) == 0) {
return S_ISREG(s.st_mode);
} else {
return false;
}
#endif
}
bool ftl::create_directory(const std::string &path) {
#ifdef WIN32
// TODO(nick)
#else
if (!is_directory(path)) {
int err = ::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
return err != -1;
}
return true;
#endif
}
optional<string> locateFile(const string &name, const vector<string> &paths) {
for (auto p : paths) {
if (is_directory(p)) {
if (is_file(p+"/"+name)) {
return p+"/"+name;
}
} else if (p.size() >= name.size() &&
p.compare(p.size() - name.size(), name.size(), name) == 0 &&
is_file(p)) {
return p;
}
}
if (is_file("./"+name)) return "./"+name;
if (is_file(string(FTL_LOCAL_CONFIG_ROOT) +"/"+ name)) return string(FTL_LOCAL_CONFIG_ROOT) +"/"+ name;
if (is_file(string(FTL_GLOBAL_CONFIG_ROOT) +"/"+ name)) return string(FTL_GLOBAL_CONFIG_ROOT) +"/"+ name;
return {};
}
/**
* Find and load a JSON configuration file
*/
static bool findConfiguration(const string &file, const vector<string> &paths,
const std::string &app) {
ifstream i;
if (file != "") i.open(file);
if (!i.is_open()) {
auto f = locateFile("config.json", paths);
if (!f) return false;
i.open(*f);
}
i >> config;
config = config[app];
return true;
}
/**
* Generate a map from command line option to value
*/
static map<string, string> read_options(char ***argv, int *argc) {
map<string, string> opts;
while (*argc > 0) {
string cmd((*argv)[0]);
if (cmd[0] != '-') break;
size_t p;
if ((p = cmd.find("=")) == string::npos) {
opts[cmd.substr(2)] = "true";
} else {
auto val = cmd.substr(p+1);
if (std::isdigit(val[0]) || val == "true" || val == "false" || val == "null") {
opts[cmd.substr(2, p-2)] = val;
} else {
if (val[0] == '\\') opts[cmd.substr(2, p-2)] = val;
else opts[cmd.substr(2, p-2)] = "\""+val+"\"";
}
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
}
(*argc)--;
(*argv)++;
}
return opts;
}
/**
* Put command line options into json config. If config element does not exist
* or is of a different type then report an error.
*/
static void process_options(const map<string, string> &opts) {
for (auto opt : opts) {
if (opt.first == "config") continue;
if (opt.first == "version") {
std::cout << "FTL Vision Node - v" << FTL_VERSION << std::endl;
std::cout << FTL_VERSION_LONG << std::endl;
exit(0);
}
try {
auto ptr = json::json_pointer("/"+opt.first);
// TODO(nick) Allow strings without quotes
auto v = json::parse(opt.second);
if (v.type() != config.at(ptr).type()) {
LOG(ERROR) << "Incorrect type for argument " << opt.first;
continue;
}
config.at(ptr) = v;
} catch(...) {
LOG(ERROR) << "Unrecognised option: " << opt.first;
}
}
}
vector<string> ftl::configure(int argc, char **argv, const std::string &app) {
argc--;
argv++;
// Process Arguments
auto options = read_options(&argv, &argc);
vector<string> paths;
while (argc-- > 0) {
paths.push_back(argv[0]);
}
if (!findConfiguration(options["config"], paths, app)) {
LOG(FATAL) << "Could not find any configuration!";
}
process_options(options);
return paths;
}