{"action":"created","comment":{"url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/comments/40699443","id":40699443,"diff_hunk":"@@ -12,131 +12,103 @@\n \n -module(couch_epi_data).\n \n--behaviour(gen_server).\n+-include(\"couch_epi.hrl\").\n \n %% ------------------------------------------------------------------\n %% API Function Exports\n %% ------------------------------------------------------------------\n \n--export([childspec/4]).\n--export([start_link/4, reload/1]).\n--export([wait/1, stop/1]).\n-\n-%% ------------------------------------------------------------------\n-%% gen_server Function Exports\n-%% ------------------------------------------------------------------\n-\n--export([init/1, handle_call/3, handle_cast/2, handle_info/2,\n-         terminate/2, code_change/3]).\n-\n--record(state, {\n-    subscriber, module, key, hash, handle,\n-    initialized = false, pending = []}).\n+-export([interval/1, data/1]).\n \n %% ------------------------------------------------------------------\n %% API Function Definitions\n %% ------------------------------------------------------------------\n \n-childspec(Id, App, EpiKey, Module) ->\n-    {\n-        Id,\n-        {?MODULE, start_link, [\n-            App,\n-            EpiKey,\n-            Module,\n-            []\n-        ]},\n-        permanent,\n-        5000,\n-        worker,\n-        [Module]\n-    }.\n-\n-start_link(SubscriberApp, {epi_key, Key}, Module, Options) ->\n-    maybe_start_keeper(Key),\n-    gen_server:start_link(?MODULE, [SubscriberApp, Module, Key, Options], []).\n-\n-reload(Server) ->\n-    gen_server:call(Server, reload).\n-\n-wait(Server) ->\n-    gen_server:call(Server, wait).\n-\n-stop(Server) ->\n-    catch gen_server:call(Server, stop).\n+interval(Specs) ->\n+    extract_minimal_interval(Specs).\n \n-%% ------------------------------------------------------------------\n-%% gen_server Function Definitions\n-%% ------------------------------------------------------------------\n-\n-init([Subscriber, Module, Key, _Options]) ->\n-    gen_server:cast(self(), init),\n-    {ok, #state{\n-        subscriber = Subscriber,\n-        module = Module,\n-        key = Key,\n-        handle = couch_epi_data_gen:get_handle(Key)}}.\n-\n-handle_call(wait, _From, #state{initialized = true} = State) ->\n-    {reply, ok, State};\n-handle_call(wait, From, #state{pending = Pending} = State) ->\n-    {noreply, State#state{pending = [From | Pending]}};\n-handle_call(reload, _From, State) ->\n-    {Res, NewState} = reload_if_updated(State),\n-    {reply, Res, NewState};\n-handle_call(stop, _From, State) ->\n-    {stop, normal, State};\n-handle_call(_Request, _From, State) ->\n-    {reply, ok, State}.\n-\n-handle_cast(init, #state{pending = Pending} = State) ->\n-    {_, NewState} = reload_if_updated(State),\n-    [gen_server:reply(Client, ok) || Client <- Pending],\n-    {noreply, NewState#state{initialized = true, pending = []}};\n-handle_cast(_Msg, State) ->\n-    {noreply, State}.\n-\n-handle_info(_Info, State) ->\n-    {noreply, State}.\n-\n-terminate(_Reason, _State) ->\n-    ok.\n-\n-code_change(_OldVsn, State, _Extra) ->\n-    {_, NewState} = reload_if_updated(State),\n-    {ok, NewState}.\n+data(Specs) ->\n+    Locators = locate_sources(Specs),\n+    case lists:foldl(fun collect_data/2, {ok, [], []}, Locators) of\n+        {ok, Hashes, Data} ->\n+            {ok, couch_epi_util:hash(Hashes), Data};\n+        Error ->\n+            Error\n+    end.\n \n %% ------------------------------------------------------------------\n %% Internal Function Definitions\n %% ------------------------------------------------------------------\n \n-reload_if_updated(#state{hash = OldHash, module = Module} = State) ->\n-    case couch_epi_functions_gen:hash([Module]) of\n-        OldHash ->\n-            {ok, State};\n-        Hash ->\n-            safe_set(Hash, State)\n+collect_data({App, Locator}, {ok, HashAcc, DataAcc}) ->\n+    case definitions(Locator) of\n+        {ok, Hash, Data} ->\n+            {ok, [Hash | HashAcc], [{App, Data} | DataAcc]};\n+        Error ->\n+            Error\n+    end;\n+collect_data({_App, _Locator}, Error) ->\n+    Error.\n+\n+extract_minimal_interval(Specs) ->\n+    lists:foldl(fun minimal_interval/2, undefined, Specs).\n+\n+minimal_interval({_App, #couch_epi_spec{options = Options}}, Min) ->\n+    case lists:keyfind(interval, 1, Options) of\n+        {interval, Interval} -> min(Interval, Min);\n+        false -> Min\n     end.\n \n-safe_set(Hash, #state{} = State) ->\n-    #state{\n-        handle = Handle,\n-        subscriber = Subscriber,\n-        module = Module,\n-        key = Key} = State,\n-    try\n-        Data = get_from_module(Module),\n-        OldData = couch_epi_data_gen:current_data(Handle, Subscriber),\n-        ok = couch_epi_data_gen:set(Handle, Subscriber, Data),\n-        couch_epi_server:notify(Subscriber, Key, {data, OldData}, {data, Data}),\n-        {ok, State#state{hash = Hash}}\n-    catch Class:Reason ->\n-        {{Class, Reason}, State}\n+locate_sources(Specs) ->\n+    lists:map(fun({ProviderApp, #couch_epi_spec{value = Src}}) ->\n+        {ok, Locator} = locate(ProviderApp, Src),\n+        {ProviderApp, Locator}\n+    end, Specs).\n+\n+locate(App, {priv_file, FileName}) ->\n+    case priv_path(App, FileName) of\n+        {ok, FilePath} ->\n+            ok = ensure_exists(FilePath),\n+            {ok, {file, FilePath}};\n+        Else ->\n+            Else\n+    end;\n+locate(_App, {file, FilePath}) ->\n+    ok = ensure_exists(FilePath),\n+    {ok, {file, FilePath}};\n+locate(_App, Locator) ->\n+    {ok, Locator}.\n+\n+priv_path(AppName, FileName) ->\n+    case code:priv_dir(AppName) of\n+        {error, _Error} = Error ->\n+            Error;\n+        Dir ->\n+            {ok, filename:join(Dir, FileName)}\n     end.\n \n-get_from_module(Module) ->\n-    Module:data().\n+ensure_exists(FilePath) ->\n+    case filelib:is_regular(FilePath) of\n+        true ->\n+            ok;\n+        false ->\n+            {error, {notfound, FilePath}}","path":"src/couch_epi_data.erl","position":188,"original_position":188,"commit_id":"0799acd8040f53235249476ee199246c078fcfec","original_commit_id":"0799acd8040f53235249476ee199246c078fcfec","user":{"login":"iilyak","id":9804420,"avatar_url":"https://avatars.githubusercontent.com/u/9804420?v=3","gravatar_id":"","url":"https://api.github.com/users/iilyak","html_url":"https://github.com/iilyak","followers_url":"https://api.github.com/users/iilyak/followers","following_url":"https://api.github.com/users/iilyak/following{/other_user}","gists_url":"https://api.github.com/users/iilyak/gists{/gist_id}","starred_url":"https://api.github.com/users/iilyak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iilyak/subscriptions","organizations_url":"https://api.github.com/users/iilyak/orgs","repos_url":"https://api.github.com/users/iilyak/repos","events_url":"https://api.github.com/users/iilyak/events{/privacy}","received_events_url":"https://api.github.com/users/iilyak/received_events","type":"User","site_admin":false},"body":"I abstracted it into a function for a cleaner error message (`{error, {FilePath, Reason}}`).","created_at":"2015-09-29T17:14:12Z","updated_at":"2015-09-29T17:14:12Z","html_url":"https://github.com/apache/couchdb-couch-epi/pull/12#discussion_r40699443","pull_request_url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12","_links":{"self":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/comments/40699443"},"html":{"href":"https://github.com/apache/couchdb-couch-epi/pull/12#discussion_r40699443"},"pull_request":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12"}}},"pull_request":{"url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12","id":46190522,"html_url":"https://github.com/apache/couchdb-couch-epi/pull/12","diff_url":"https://github.com/apache/couchdb-couch-epi/pull/12.diff","patch_url":"https://github.com/apache/couchdb-couch-epi/pull/12.patch","issue_url":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/12","number":12,"state":"open","locked":false,"title":"Simplify couch epi","user":{"login":"iilyak","id":9804420,"avatar_url":"https://avatars.githubusercontent.com/u/9804420?v=3","gravatar_id":"","url":"https://api.github.com/users/iilyak","html_url":"https://github.com/iilyak","followers_url":"https://api.github.com/users/iilyak/followers","following_url":"https://api.github.com/users/iilyak/following{/other_user}","gists_url":"https://api.github.com/users/iilyak/gists{/gist_id}","starred_url":"https://api.github.com/users/iilyak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iilyak/subscriptions","organizations_url":"https://api.github.com/users/iilyak/orgs","repos_url":"https://api.github.com/users/iilyak/repos","events_url":"https://api.github.com/users/iilyak/events{/privacy}","received_events_url":"https://api.github.com/users/iilyak/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-09-28T18:26:06Z","updated_at":"2015-09-29T17:14:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b0888cbd8d4c3edd5427f64a2e46c8a6cfc7cf4f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12/commits","review_comments_url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12/comments","review_comment_url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/12/comments","statuses_url":"https://api.github.com/repos/apache/couchdb-couch-epi/statuses/0799acd8040f53235249476ee199246c078fcfec","head":{"label":"cloudant:simplify_couch_epi","ref":"simplify_couch_epi","sha":"0799acd8040f53235249476ee199246c078fcfec","user":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"repo":{"id":39010274,"name":"couchdb-couch-epi","full_name":"cloudant/couchdb-couch-epi","owner":{"login":"cloudant","id":44642,"avatar_url":"https://avatars.githubusercontent.com/u/44642?v=3","gravatar_id":"","url":"https://api.github.com/users/cloudant","html_url":"https://github.com/cloudant","followers_url":"https://api.github.com/users/cloudant/followers","following_url":"https://api.github.com/users/cloudant/following{/other_user}","gists_url":"https://api.github.com/users/cloudant/gists{/gist_id}","starred_url":"https://api.github.com/users/cloudant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cloudant/subscriptions","organizations_url":"https://api.github.com/users/cloudant/orgs","repos_url":"https://api.github.com/users/cloudant/repos","events_url":"https://api.github.com/users/cloudant/events{/privacy}","received_events_url":"https://api.github.com/users/cloudant/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cloudant/couchdb-couch-epi","description":"Mirror of Apache CouchDB Couch EPI","fork":true,"url":"https://api.github.com/repos/cloudant/couchdb-couch-epi","forks_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/forks","keys_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/teams","hooks_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/hooks","issue_events_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/issues/events{/number}","events_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/events","assignees_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/assignees{/user}","branches_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/branches{/branch}","tags_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/tags","blobs_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/git/refs{/sha}","trees_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/statuses/{sha}","languages_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/languages","stargazers_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/stargazers","contributors_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/contributors","subscribers_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/subscribers","subscription_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/subscription","commits_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/commits{/sha}","git_commits_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/git/commits{/sha}","comments_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/comments{/number}","issue_comment_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/issues/comments{/number}","contents_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/contents/{+path}","compare_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/merges","archive_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/downloads","issues_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/issues{/number}","pulls_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/pulls{/number}","milestones_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/milestones{/number}","notifications_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/labels{/name}","releases_url":"https://api.github.com/repos/cloudant/couchdb-couch-epi/releases{/id}","created_at":"2015-07-13T12:18:29Z","updated_at":"2015-07-13T12:18:30Z","pushed_at":"2015-09-28T20:25:45Z","git_url":"git://github.com/cloudant/couchdb-couch-epi.git","ssh_url":"git@github.com:cloudant/couchdb-couch-epi.git","clone_url":"https://github.com/cloudant/couchdb-couch-epi.git","svn_url":"https://github.com/cloudant/couchdb-couch-epi","homepage":null,"size":164,"stargazers_count":0,"watchers_count":0,"language":"Erlang","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"aa72f6ffcc9c7095ed59b4d56f5f8139a5205a1f","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":37902675,"name":"couchdb-couch-epi","full_name":"apache/couchdb-couch-epi","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/couchdb-couch-epi","description":"Mirror of Apache CouchDB Couch EPI","fork":false,"url":"https://api.github.com/repos/apache/couchdb-couch-epi","forks_url":"https://api.github.com/repos/apache/couchdb-couch-epi/forks","keys_url":"https://api.github.com/repos/apache/couchdb-couch-epi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/couchdb-couch-epi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/couchdb-couch-epi/teams","hooks_url":"https://api.github.com/repos/apache/couchdb-couch-epi/hooks","issue_events_url":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/events{/number}","events_url":"https://api.github.com/repos/apache/couchdb-couch-epi/events","assignees_url":"https://api.github.com/repos/apache/couchdb-couch-epi/assignees{/user}","branches_url":"https://api.github.com/repos/apache/couchdb-couch-epi/branches{/branch}","tags_url":"https://api.github.com/repos/apache/couchdb-couch-epi/tags","blobs_url":"https://api.github.com/repos/apache/couchdb-couch-epi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/couchdb-couch-epi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/couchdb-couch-epi/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/couchdb-couch-epi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/couchdb-couch-epi/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/couchdb-couch-epi/languages","stargazers_url":"https://api.github.com/repos/apache/couchdb-couch-epi/stargazers","contributors_url":"https://api.github.com/repos/apache/couchdb-couch-epi/contributors","subscribers_url":"https://api.github.com/repos/apache/couchdb-couch-epi/subscribers","subscription_url":"https://api.github.com/repos/apache/couchdb-couch-epi/subscription","commits_url":"https://api.github.com/repos/apache/couchdb-couch-epi/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/couchdb-couch-epi/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/couchdb-couch-epi/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/couchdb-couch-epi/contents/{+path}","compare_url":"https://api.github.com/repos/apache/couchdb-couch-epi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/couchdb-couch-epi/merges","archive_url":"https://api.github.com/repos/apache/couchdb-couch-epi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/couchdb-couch-epi/downloads","issues_url":"https://api.github.com/repos/apache/couchdb-couch-epi/issues{/number}","pulls_url":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/couchdb-couch-epi/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/couchdb-couch-epi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/couchdb-couch-epi/labels{/name}","releases_url":"https://api.github.com/repos/apache/couchdb-couch-epi/releases{/id}","created_at":"2015-06-23T07:00:05Z","updated_at":"2015-06-26T18:58:50Z","pushed_at":"2015-09-28T20:25:46Z","git_url":"git://github.com/apache/couchdb-couch-epi.git","ssh_url":"git@github.com:apache/couchdb-couch-epi.git","clone_url":"https://github.com/apache/couchdb-couch-epi.git","svn_url":"https://github.com/apache/couchdb-couch-epi","homepage":null,"size":247,"stargazers_count":1,"watchers_count":1,"language":"Erlang","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3,"mirror_url":"git://git.apache.org/couchdb-couch-epi.git","open_issues_count":5,"forks":3,"open_issues":5,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12"},"html":{"href":"https://github.com/apache/couchdb-couch-epi/pull/12"},"issue":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/12"},"comments":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/issues/12/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/pulls/12/commits"},"statuses":{"href":"https://api.github.com/repos/apache/couchdb-couch-epi/statuses/0799acd8040f53235249476ee199246c078fcfec"}}}}