Skip to content

Commit

Permalink
modify function 'relative_to' in class parseable for solving missing …
Browse files Browse the repository at this point in the history
…relative file path problem of include statements in hocon files.(A test case is added into conf_parser_test.cc)
  • Loading branch information
SeaTalk committed Jan 31, 2019
1 parent c710b8c commit d865508
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 16 deletions.
12 changes: 12 additions & 0 deletions lib/inc/hocon/config_include_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace hocon {
*/
class LIBCPP_HOCON_EXPORT config_include_context {
public:
config_include_context() : _cur_dir(new std::string("")) {}
/**
* Tries to find a name relative to whatever is doing the including, for
* example in the same directory as the file doing the including. Returns
Expand All @@ -46,6 +47,17 @@ namespace hocon {
* @return the parse options
*/
virtual config_parse_options parse_options() const = 0;

void set_cur_dir(std::string dir) const {
_cur_dir->assign(dir);
}

std::string get_cur_dir() const {
return *_cur_dir;
}

protected:
std::shared_ptr<std::string> _cur_dir;
};

} // namespace hocon
4 changes: 4 additions & 0 deletions lib/inc/internal/parseable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ namespace hocon {
virtual std::shared_ptr<config_parseable> relative_to(std::string file_name) const;

std::string to_string() const;
std::string get_cur_dir() const;
void set_cur_dir(std::string dir) const;
void separate_filepath(const std::string& path, std::string* file_dir,
std::string* file_name) const;

// Disable copy constructors, as include_context assumes it can hold a reference to parseable.
parseable() = default;
Expand Down
29 changes: 27 additions & 2 deletions lib/inc/internal/simple_includer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,31 @@ namespace hocon {

class name_source {
public:
name_source(shared_include_context context) : _context(move(context)) {
if (nullptr != _context) {
_init_finished = true;
} else {
_init_finished = false;
}
}
name_source() : name_source(nullptr) {}
virtual shared_parseable name_to_parseable(std::string name,
config_parse_options parse_options) const = 0;

void set_context(shared_include_context context) {
if (!_init_finished) {
_init_finished = true;
_context = context;
}
}

bool context_initialed() {
return _init_finished;
}

protected:
shared_include_context _context;
bool _init_finished;
};

class relative_name_source : public name_source {
Expand All @@ -66,12 +89,14 @@ namespace hocon {

shared_parseable name_to_parseable(std::string name,
config_parse_options parse_options) const override;
private:
const shared_include_context _context;
};

class file_name_source : public name_source {
public:
file_name_source();

file_name_source(shared_include_context context);

shared_parseable name_to_parseable(std::string name,
config_parse_options parse_options) const override;
};
Expand Down
41 changes: 33 additions & 8 deletions lib/src/parseable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,44 @@ namespace hocon {
}

shared_ptr<config_parseable> parseable::relative_to(string file_name) const {
// fall back to classpath; we treat the "filename" as absolute
// (don't add a package name in front),
// if it starts with "/" then remove the "/", for consistency
// with parseable_resrouces.relativeTo
// we don't have classpath or resoucespath in c++. (it does in Java)
// we treat the "filename" as absolute or relative path
// to a specific hocon file. (URL is not supported now)
// if it starts with "/", we consider it as a absolute path.
// otherwise, it's a relative path.
string resource = file_name;
if (boost::algorithm::starts_with(file_name, "/")) {
resource = file_name.substr(1);
if (!file_name.empty() && '/' == file_name[0]) {
resource = file_name;
} else {
resource = get_cur_dir() + file_name;
}
return make_shared<parseable_resources>(resource,
options().set_origin_description(nullptr));
return parseable::new_file(move(resource), _include_context->parse_options());
}

string parseable::to_string() const {
return typeid(*this).name();
}

void parseable::set_cur_dir(std::string dir) const {
_include_context->set_cur_dir(move(dir));
}

std::string parseable::get_cur_dir() const {
return _include_context->get_cur_dir();
}

void parseable::separate_filepath(const std::string& path, std::string* file_dir, std::string* file_name) const {
char sep = '/';
size_t i = path.rfind(sep, path.length());
if (std::string::npos != i) {
file_dir->assign(path.substr(0, i + 1));
file_name->assign(path.substr(i + 1, path.length() - i));
} else {
file_dir->assign("");
file_name->assign(path);
}
}

shared_ptr<config_document> parseable::parse_config_document() {
return parse_document(_initial_options);
}
Expand Down Expand Up @@ -271,6 +293,9 @@ namespace hocon {
parseable_file::parseable_file(std::string input_file_path, config_parse_options options) :
_input(move(input_file_path)) {
post_construct(options);
string dir, name;
separate_filepath(_input, &dir, &name);
set_cur_dir(dir);
}

unique_ptr<istream> parseable_file::reader() const {
Expand Down
35 changes: 29 additions & 6 deletions lib/src/simple_includer.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <hocon/config.hpp>
#include <internal/simple_includer.hpp>
#include <internal/simple_include_context.hpp>
#include <internal/values/simple_config_object.hpp>
#include <internal/parseable.hpp>
#include <hocon/config_exception.hpp>
Expand Down Expand Up @@ -58,7 +59,11 @@ namespace hocon {
}

shared_object simple_includer::include_file_without_fallback(shared_include_context context, std::string what) {
return config::parse_file_any_syntax(move(what), context->parse_options())->resolve(config_resolve_options(true, true))->root();
auto source = make_shared<file_name_source>(context);
return from_basename(move(source), what, context->parse_options())
->to_config()
->resolve(config_resolve_options(true, true))
->root();
}

config_parse_options simple_includer::clear_for_include(config_parse_options const& options) {
Expand All @@ -76,11 +81,18 @@ namespace hocon {
config_parse_options options) {
shared_object obj;
if (boost::algorithm::ends_with(name, ".conf") || boost::algorithm::ends_with(name, ".json")) {
auto p = source->name_to_parseable(name, options);
shared_parseable p(nullptr);
if (source->context_initialed()) {
p = source->name_to_parseable(name, options);
} else {
p = parseable::new_file(name, options);
source->set_context(
make_shared<simple_include_context>(*(dynamic_pointer_cast<const parseable>(p))));
}
obj = p->parse(p->options().set_allow_missing(options.get_allow_missing()));
} else {
auto conf_handle = source->name_to_parseable(name + ".conf", options);
auto json_handle = source->name_to_parseable(name + ".json", options);
auto conf_handle = parseable::new_file(name + ".conf", options);
auto json_handle = parseable::new_file(name + ".json", options);
bool got_something = false;
vector<config_exception> fails;

Expand Down Expand Up @@ -137,7 +149,7 @@ namespace hocon {

/** Relative name source */
relative_name_source::relative_name_source(shared_include_context context) :
_context(move(context)) {}
name_source(move(context)) {}

shared_parseable relative_name_source::name_to_parseable(string name,
config_parse_options parse_options) const {
Expand All @@ -151,8 +163,19 @@ namespace hocon {
}

/** File name source */
file_name_source::file_name_source() : name_source() {}

file_name_source::file_name_source(shared_include_context context) :
name_source(move(context)) {}

shared_parseable file_name_source::name_to_parseable(std::string name, config_parse_options parse_options) const {
return parseable::new_file(move(name), move(parse_options));
auto p = _context->relative_to(name);
if (p == nullptr) {
// avoid returning null
return parseable::new_not_found(name, _("include was not found: '{1}'", name), move(parse_options));
} else {
return p;
}
}

/** Proxy */
Expand Down
16 changes: 16 additions & 0 deletions lib/tests/conf_parser_test.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <catch.hpp>
#include "test_utils.hpp"
#include "fixtures.hpp"

#include <boost/algorithm/string/replace.hpp>

Expand Down Expand Up @@ -718,3 +719,18 @@ TEST_CASE("accept multi period numeric path") {
auto conf3 = config::parse_string("ABC.0.1.2.3=foobar3");
REQUIRE("foobar3" == conf3->get_string("ABC.0.1.2.3"));
}


TEST_CASE("parse files") {
string cur_file_path(TEST_FILE_DIR);
string file_path1 = cur_file_path + "/simple_confs/a.conf";
string file_path2 = cur_file_path + "/simple_confs/sub/b.conf";
auto conf1 = config::parse_file_any_syntax(move(file_path1))->resolve();
auto conf2 = config::parse_file_any_syntax(move(file_path2))->resolve();
REQUIRE("adsf" == conf1->get_string("Peter.passwd1"));
REQUIRE("lsdk" == conf1->get_string("Peter.passwd2"));
REQUIRE("123414" == conf1->get_string("Peter.passwd3"));
REQUIRE("qwer.,m" == conf1->get_string("Peter.passwd4"));
REQUIRE(10 == conf1->get_int("Peter.passwd5"));
REQUIRE("nick" == conf2->get_string("other_field.nick_name"));
}
11 changes: 11 additions & 0 deletions lib/tests/simple_confs/a.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
include file("d.conf")
Peter : {
include file("b.conf")
include file("sub/b.conf")
passwd4 : ${new_passwd}
passwd5 : 10
}

}

4 changes: 4 additions & 0 deletions lib/tests/simple_confs/b.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
passwd1 : "adsf"
include file("sub/c.conf")
}
3 changes: 3 additions & 0 deletions lib/tests/simple_confs/d.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
new_passwd : "qwer.,m"
}
7 changes: 7 additions & 0 deletions lib/tests/simple_confs/sub/b.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
passwd2 : "lsdk" ,

other_field : {
include file("e.conf")
}
}
3 changes: 3 additions & 0 deletions lib/tests/simple_confs/sub/c.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
passwd3 : "123414",
}
3 changes: 3 additions & 0 deletions lib/tests/simple_confs/sub/e.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
nick_name : nick
}

0 comments on commit d865508

Please sign in to comment.