diff --git a/src/cuttlefish_conf.erl b/src/cuttlefish_conf.erl index f22121df..bc84204d 100644 --- a/src/cuttlefish_conf.erl +++ b/src/cuttlefish_conf.erl @@ -24,8 +24,8 @@ -export([ generate/1, generate_file/2, - file/1, - files/1, + file/2, + files/2, is_variable_defined/2, pretty_datatype/1]). @@ -38,11 +38,11 @@ is_variable_defined(VariableDef, Conf) -> lists:any(fun({X, _}) -> cuttlefish_variable:is_fuzzy_match(X, VariableDef) end, Conf). --spec files([file:name()]) -> conf() | cuttlefish_error:errorlist(). -files(ListOfConfFiles) -> +-spec files([file:name()], atom()) -> conf() | cuttlefish_error:errorlist(). +files(ListOfConfFiles, ParserMod) -> {ValidConf, Errors} = lists:foldl( fun(ConfFile, {ConfAcc, ErrorAcc}) -> - case cuttlefish_conf:file(ConfFile) of + case cuttlefish_conf:file(ConfFile, ParserMod) of {errorlist, ErrorList} -> {ConfAcc, ErrorList ++ ErrorAcc}; Conf -> @@ -61,9 +61,9 @@ files(ListOfConfFiles) -> _ -> {errorlist, Errors} end. --spec file(file:name()) -> conf() | cuttlefish_error:errorlist(). -file(Filename) -> - case conf_parse:file(Filename) of +-spec file(file:name(), atom()) -> conf() | cuttlefish_error:errorlist(). +file(Filename, ParserMod) -> + case ParserMod:file(Filename) of {error, Reason} -> %% Reason is an atom via file:open {errorlist, [{error, {file_open, {Filename, Reason}}}]}; diff --git a/src/cuttlefish_escript.erl b/src/cuttlefish_escript.erl index 81c932c6..795e3f98 100644 --- a/src/cuttlefish_escript.erl +++ b/src/cuttlefish_escript.erl @@ -33,17 +33,18 @@ cli_options() -> %% Option Name, Short Code, Long Code, Argument Spec, Help Message [ - {help, $h, "help", undefined, "Print this usage page"}, - {etc_dir, $e, "etc_dir", {string, "/etc"}, "etc dir"}, - {dest_dir, $d, "dest_dir", string, "specifies the directory to write the config file to"}, - {dest_file, $f, "dest_file", {string, "app"}, "the file name to write"}, - {schema_dir, $s, "schema_dir", string, "a directory containing .schema files"}, - {schema_file, $i, "schema_file", string, "individual schema file, will be processed in command line order, after -s"}, - {conf_file, $c, "conf_file", string, "a cuttlefish conf file, multiple files allowed"}, - {app_config, $a, "app_config", string, "the advanced erlangy app.config"}, - {log_level, $l, "log_level", {string, "notice"}, "log level for cuttlefish output"}, - {print_schema, $p, "print", undefined, "prints schema mappings on stderr"}, - {max_history, $m, "max_history", {integer, 3}, "the maximum number of generated config files to keep"} + {help, $h, "help", undefined, "Print this usage page"}, + {etc_dir, $e, "etc_dir", {string, "/etc"}, "etc dir"}, + {dest_dir, $d, "dest_dir", string, "specifies the directory to write the config file to"}, + {dest_file, $f, "dest_file", {string, "app"}, "the file name to write"}, + {schema_dir, $s, "schema_dir", string, "a directory containing .schema files"}, + {schema_file, $i, "schema_file", string, "individual schema file, will be processed in command line order, after -s"}, + {conf_file, $c, "conf_file", string, "a cuttlefish conf file, multiple files allowed"}, + {app_config, $a, "app_config", string, "the advanced erlangy app.config"}, + {log_level, $l, "log_level", {string, "notice"}, "log level for cuttlefish output"}, + {print_schema, $p, "print", undefined, "prints schema mappings on stderr"}, + {max_history, $m, "max_history", {integer, 3}, "the maximum number of generated config files to keep"}, + {parser, undefined, "parser", atom, "parser module to parse config file"} ]. %% LOL! I wanted this to be halt 0, but honestly, if this escript does anything @@ -303,8 +304,13 @@ load_schema(ParsedArgs) -> load_conf(ParsedArgs) -> ConfFiles = proplists:get_all_values(conf_file, ParsedArgs), + Parser = proplists:get_value(parser, ParsedArgs), + ParserMod = case Parser of + undefined -> conf_parse; + _ -> ensure_parser(Parser) + end, lager:debug("ConfFiles: ~p", [ConfFiles]), - case cuttlefish_conf:files(ConfFiles) of + case cuttlefish_conf:files(ConfFiles, ParserMod) of {errorlist, Errors} -> _ = [ lager:error(cuttlefish_error:xlate(E)) || {error, E} <- Errors], @@ -314,6 +320,23 @@ load_conf(ParsedArgs) -> GoodConf end. +ensure_parser(Module) -> + case code:ensure_loaded(Module) of + {module, Module} -> + case erlang:function_exported(Module, file, 1) of + true -> Module; + false -> + lager:error("Unable to parse config. No function ~p:file/1 exported", [Module]), + stop_deactivate(), + {error, function_not_exported} + + end; + {error, Reason} -> + lager:error("Unable to parse config. Unable to load parser module ~p. Reason: ~p", [Module, Reason]), + stop_deactivate(), + {error, Reason} + end. + -spec writable_destination_path([proplists:property()]) -> file:filename() | error. writable_destination_path(ParsedArgs) -> EtcDir = proplists:get_value(etc_dir, ParsedArgs), diff --git a/src/cuttlefish_parse.erl b/src/cuttlefish_parse.erl new file mode 100644 index 00000000..dbb2acde --- /dev/null +++ b/src/cuttlefish_parse.erl @@ -0,0 +1,9 @@ +-module(cuttlefish_parse). + +-type variable() :: [string()]. +-type conf() :: [{variable(), term()}]. +-type parse_result() :: {error, term()} + | {conf(), binary(), {{line, integer()}, {column, integer()}}} + | conf(). + +-callback file(iolist()) -> parse_result(). \ No newline at end of file