diff options
Diffstat (limited to 'src/couchdb/couch_config.erl')
-rw-r--r-- | src/couchdb/couch_config.erl | 254 |
1 files changed, 0 insertions, 254 deletions
diff --git a/src/couchdb/couch_config.erl b/src/couchdb/couch_config.erl deleted file mode 100644 index 792ff5a0..00000000 --- a/src/couchdb/couch_config.erl +++ /dev/null @@ -1,254 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - -% Reads CouchDB's ini file and gets queried for configuration parameters. -% This module is initialized with a list of ini files that it consecutively -% reads Key/Value pairs from and saves them in an ets table. If more an one -% ini file is specified, the last one is used to write changes that are made -% with store/2 back to that ini file. - --module(couch_config). --behaviour(gen_server). - --include("couch_db.hrl"). - - --export([start_link/1, stop/0]). --export([all/0, get/1, get/2, get/3, set/3, set/4, delete/2, delete/3]). --export([register/1, register/2]). --export([parse_ini_file/1]). - --export([init/1, terminate/2, code_change/3]). --export([handle_call/3, handle_cast/2, handle_info/2]). - --record(config, { - notify_funs=[], - write_filename=undefined -}). - - -start_link(IniFiles) -> - gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []). - -stop() -> - gen_server:cast(?MODULE, stop). - - -all() -> - lists:sort(gen_server:call(?MODULE, all, infinity)). - - -get(Section) when is_binary(Section) -> - ?MODULE:get(?b2l(Section)); -get(Section) -> - Matches = ets:match(?MODULE, {{Section, '$1'}, '$2'}), - [{Key, Value} || [Key, Value] <- Matches]. - -get(Section, Key) -> - ?MODULE:get(Section, Key, undefined). - -get(Section, Key, Default) when is_binary(Section) and is_binary(Key) -> - ?MODULE:get(?b2l(Section), ?b2l(Key), Default); -get(Section, Key, Default) -> - case ets:lookup(?MODULE, {Section, Key}) of - [] -> Default; - [{_, Match}] -> Match - end. - -set(Section, Key, Value) -> - ?MODULE:set(Section, Key, Value, true). - -set(Section, Key, Value, Persist) when is_binary(Section) and is_binary(Key) -> - ?MODULE:set(?b2l(Section), ?b2l(Key), Value, Persist); -set(Section, Key, Value, Persist) -> - gen_server:call(?MODULE, {set, Section, Key, Value, Persist}). - - -delete(Section, Key) when is_binary(Section) and is_binary(Key) -> - delete(?b2l(Section), ?b2l(Key)); -delete(Section, Key) -> - delete(Section, Key, true). - -delete(Section, Key, Persist) when is_binary(Section) and is_binary(Key) -> - delete(?b2l(Section), ?b2l(Key), Persist); -delete(Section, Key, Persist) -> - gen_server:call(?MODULE, {delete, Section, Key, Persist}). - - -register(Fun) -> - ?MODULE:register(Fun, self()). - -register(Fun, Pid) -> - gen_server:call(?MODULE, {register, Fun, Pid}). - - -init(IniFiles) -> - ets:new(?MODULE, [named_table, set, protected]), - try - lists:map(fun(IniFile) -> - {ok, ParsedIniValues} = parse_ini_file(IniFile), - ets:insert(?MODULE, ParsedIniValues) - end, IniFiles), - WriteFile = case IniFiles of - [_|_] -> lists:last(IniFiles); - _ -> undefined - end, - {ok, #config{write_filename = WriteFile}} - catch _Tag:Error -> - {stop, Error} - end. - - -terminate(_Reason, _State) -> - ok. - - -handle_call(all, _From, Config) -> - Resp = lists:sort((ets:tab2list(?MODULE))), - {reply, Resp, Config}; -handle_call({set, Sec, Key, Val, Persist}, From, Config) -> - Result = case {Persist, Config#config.write_filename} of - {true, undefined} -> - ok; - {true, FileName} -> - couch_config_writer:save_to_file({{Sec, Key}, Val}, FileName); - _ -> - ok - end, - case Result of - ok -> - true = ets:insert(?MODULE, {{Sec, Key}, Val}), - spawn_link(fun() -> - [catch F(Sec, Key, Val, Persist) || {_Pid, F} <- Config#config.notify_funs], - gen_server:reply(From, ok) - end), - {noreply, Config}; - _Error -> - {reply, Result, Config} - end; -handle_call({delete, Sec, Key, Persist}, From, Config) -> - true = ets:delete(?MODULE, {Sec,Key}), - case {Persist, Config#config.write_filename} of - {true, undefined} -> - ok; - {true, FileName} -> - couch_config_writer:save_to_file({{Sec, Key}, ""}, FileName); - _ -> - ok - end, - spawn_link(fun() -> - [catch F(Sec, Key, deleted, Persist) || {_Pid, F} <- Config#config.notify_funs], - gen_server:reply(From, ok) - end), - {noreply, Config}; -handle_call({register, Fun, Pid}, _From, #config{notify_funs=PidFuns}=Config) -> - erlang:monitor(process, Pid), - % convert 1 and 2 arity to 3 arity - Fun2 = - case Fun of - _ when is_function(Fun, 1) -> - fun(Section, _Key, _Value, _Persist) -> Fun(Section) end; - _ when is_function(Fun, 2) -> - fun(Section, Key, _Value, _Persist) -> Fun(Section, Key) end; - _ when is_function(Fun, 3) -> - fun(Section, Key, Value, _Persist) -> Fun(Section, Key, Value) end; - _ when is_function(Fun, 4) -> - Fun - end, - {reply, ok, Config#config{notify_funs=[{Pid, Fun2} | PidFuns]}}. - - -handle_cast(stop, State) -> - {stop, normal, State}; -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_info({'DOWN', _, _, DownPid, _}, #config{notify_funs=PidFuns}=Config) -> - % remove any funs registered by the downed process - FilteredPidFuns = [{Pid,Fun} || {Pid,Fun} <- PidFuns, Pid /= DownPid], - {noreply, Config#config{notify_funs=FilteredPidFuns}}. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - - -parse_ini_file(IniFile) -> - IniFilename = couch_util:abs_pathname(IniFile), - IniBin = - case file:read_file(IniFilename) of - {ok, IniBin0} -> - IniBin0; - {error, eacces} -> - throw({file_permission_error, IniFile}); - {error, enoent} -> - Fmt = "Couldn't find server configuration file ~s.", - Msg = ?l2b(io_lib:format(Fmt, [IniFilename])), - ?LOG_ERROR("~s~n", [Msg]), - throw({startup_error, Msg}) - end, - - Lines = re:split(IniBin, "\r\n|\n|\r|\032", [{return, list}]), - {_, ParsedIniValues} = - lists:foldl(fun(Line, {AccSectionName, AccValues}) -> - case string:strip(Line) of - "[" ++ Rest -> - case re:split(Rest, "\\]", [{return, list}]) of - [NewSectionName, ""] -> - {NewSectionName, AccValues}; - _Else -> % end bracket not at end, ignore this line - {AccSectionName, AccValues} - end; - ";" ++ _Comment -> - {AccSectionName, AccValues}; - Line2 -> - case re:split(Line2, "\s?=\s?", [{return, list}]) of - [Value] -> - MultiLineValuePart = case re:run(Line, "^ \\S", []) of - {match, _} -> - true; - _ -> - false - end, - case {MultiLineValuePart, AccValues} of - {true, [{{_, ValueName}, PrevValue} | AccValuesRest]} -> - % remove comment - case re:split(Value, " ;|\t;", [{return, list}]) of - [[]] -> - % empty line - {AccSectionName, AccValues}; - [LineValue | _Rest] -> - E = {{AccSectionName, ValueName}, - PrevValue ++ " " ++ LineValue}, - {AccSectionName, [E | AccValuesRest]} - end; - _ -> - {AccSectionName, AccValues} - end; - [""|_LineValues] -> % line begins with "=", ignore - {AccSectionName, AccValues}; - [ValueName|LineValues] -> % yeehaw, got a line! - RemainingLine = couch_util:implode(LineValues, "="), - % removes comments - case re:split(RemainingLine, " ;|\t;", [{return, list}]) of - [[]] -> - % empty line means delete this key - ets:delete(?MODULE, {AccSectionName, ValueName}), - {AccSectionName, AccValues}; - [LineValue | _Rest] -> - {AccSectionName, - [{{AccSectionName, ValueName}, LineValue} | AccValues]} - end - end - end - end, {"", []}, Lines), - {ok, ParsedIniValues}. - |