36 namespace fable::schema {
41 const char* path_state_cstr(PathState e);
45 template <
typename TPath>
46 bool exists(
const TPath& path);
48 template <
typename TPath>
49 bool is_regular_file(
const TPath& path);
51 template <
typename TPath>
52 bool is_directory(
const TPath& path);
54 template <
typename TPath>
55 bool is_other(
const TPath& path);
57 template <
typename TPath>
58 TPath canonical(
const TPath& path);
60 template <
typename TPath>
61 std::optional<TPath> search_path(
const TPath& executable);
70 if (!pattern_.empty()) {
71 j[
"pattern"] = pattern_;
73 if (min_length_ != 0) {
74 j[
"minLength"] = min_length_;
76 if (max_length_ != std::numeric_limits<size_t>::max()) {
77 j[
"maxLength"] = max_length_;
80 if (req_state_ != State::Any) {
81 j[
"comment"] = detail::path_state_cstr(req_state_);
84 this->augment_schema(j);
90 if (!this->validate_type(c, err)) {
94 auto src = c.
get<std::string>();
97 src = interpolate_vars(src, env_);
98 }
catch (std::invalid_argument& e) {
100 return this->set_error(err, c,
"error interpolating variable in path: {}", e.what());
103 if (src.size() < min_length_) {
104 return this->set_error(err, c,
"expect minimum path length of {}, got {}", min_length_,
107 if (src.size() > max_length_) {
108 return this->set_error(err, c,
"expect maximum path length of {}, got {}", max_length_,
111 if (!pattern_.empty() && !std::regex_match(src, std::regex(pattern_))) {
112 return this->set_error(err, c,
"expect path to match regex '{}': {}", pattern_, src);
116 if (req_abs_ && !p.is_absolute()) {
117 return this->set_error(err, c,
"expect path to be absolute: {}", src);
121 p = resolve_path(c, p);
123 err.emplace(std::move(e));
128 switch (req_state_) {
130 if (detail::exists(p)) {
131 return this->set_error(err, c, detail::path_state_cstr(req_state_));
135 if (!detail::exists(p)) {
136 return this->set_error(err, c, detail::path_state_cstr(req_state_));
139 case State::Executable:
141 case State::FileExists:
142 if (!detail::is_regular_file(p)) {
143 return this->set_error(err, c, detail::path_state_cstr(req_state_));
146 case State::DirExists:
147 if (!detail::is_directory(p)) {
148 return this->set_error(err, c, detail::path_state_cstr(req_state_));
152 if (detail::is_regular_file(p) || detail::is_other(p)) {
153 return this->set_error(err, c, detail::path_state_cstr(req_state_));
157 if (detail::is_directory(p)) {
158 return this->set_error(err, c, detail::path_state_cstr(req_state_));
168 template <
typename T>
170 auto s = c.
get<std::string>();
172 s = interpolate_vars(s, env_);
176 p = resolve_path(c, p);
179 p = detail::canonical(p);
184 template <
typename T>
185 typename Path<T>::Type Path<T>::resolve_path(
const Conf& c,
const Path<T>::Type& filepath)
const {
186 std::string filepath_str = filepath.generic_string();
190 if (req_state_ == State::Executable && filepath_str.find(
'/') == std::string::npos) {
191 auto result = detail::search_path(filepath);
193 throw this->error(c,
"expect executable to exist: {}", filepath.native());
197 return c.resolve_file(filepath_str);
T get() const
Definition: conf.hpp:297
Definition: error.hpp:149
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: path_impl.hpp:89
Json json_schema() const override
Definition: path_impl.hpp:66
nlohmann::json Json
Definition: fable_fwd.hpp:35