Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 342 lines (295 sloc) 12.391 kb
44a5bb4 @jlouis Hint Emacs that the Tab Stop of the files are 4 spaces.
jlouis authored
1 %% -*- Mode: Erlang; tab-width: 4 -*-
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
2 -module(agner_server).
3 -include_lib("agner.hrl").
4 -include_lib("typespecs/include/typespecs.hrl").
5 -behaviour(gen_server).
6
7 %% API
8 -export([start_link/0]).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
9 -export([spec/2, spec_url/2, index/0, fetch/3, versions/1]).
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
10
11 %% gen_server callbacks
12 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
13 terminate/2, code_change/3]).
14
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
15 -define(SERVER, ?MODULE).
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
16
376e447 @yrashk Increate requests timeouts in agner_server public API
yrashk authored
17 -define(TIMEOUT, 60000).
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
18
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
19 -record(state, {
20 }).
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
21
22 -type gen_server_state() :: #state{}.
23
24 %%%===================================================================
25 %%% API
26 %%%===================================================================
27
28 %%--------------------------------------------------------------------
29 %% @doc
30 %% Starts the server
31 %%
32 %% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
33 %% @end
34 %%--------------------------------------------------------------------
35 start_link() ->
36 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
37
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
38 %% @doc Ask the server for a spec on Name and Version
39 %% @end
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
40 -spec spec(agner_package_name(), agner_package_version()) -> agner_spec().
4649870 @yrashk Added some typespecs, primarily in agner_server
yrashk authored
41
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
42 spec(Name, Version) ->
376e447 @yrashk Increate requests timeouts in agner_server public API
yrashk authored
43 gen_server:call(?SERVER, {spec, Name, Version}, ?TIMEOUT).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
44
45 %% @doc Ask the server for a spec URL
46 %% @end
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
47 -spec spec_url(agner_package_name(), agner_package_version()) -> url().
4649870 @yrashk Added some typespecs, primarily in agner_server
yrashk authored
48
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
49 spec_url(Name, Version) ->
376e447 @yrashk Increate requests timeouts in agner_server public API
yrashk authored
50 gen_server:call(?SERVER, {spec_url, Name, Version}, ?TIMEOUT).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
51
52 %% @doc Ask the server for an index
53 %% @end
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
54 -spec index() -> list(agner_package_name()).
4649870 @yrashk Added some typespecs, primarily in agner_server
yrashk authored
55
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
56 index() ->
376e447 @yrashk Increate requests timeouts in agner_server public API
yrashk authored
57 gen_server:call(?SERVER, index, infinity).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
58
59 %% @doc Fetch a package/project to a directory
60 %% @end
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
61 -spec fetch(agner_package_name(), agner_package_version(), directory()) -> ok | not_found_error();
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
62 (agner_spec(), any(), directory()) -> ok | not_found_error().
4649870 @yrashk Added some typespecs, primarily in agner_server
yrashk authored
63
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
64 fetch(NameOrSpec, Version, Directory) ->
65 gen_server:call(?SERVER, {fetch, NameOrSpec, Version, Directory}, infinity).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
66
67 %% @doc Ask for the versions of a given package, Name
68 %% @end
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
69 -spec versions(agner_package_name()) -> list(agner_package_version()).
4649870 @yrashk Added some typespecs, primarily in agner_server
yrashk authored
70
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
71 versions(Name) ->
376e447 @yrashk Increate requests timeouts in agner_server public API
yrashk authored
72 gen_server:call(?SERVER, {versions, Name},?TIMEOUT).
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
73
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
74 %%%===================================================================
75 %%% gen_server callbacks
76 %%%===================================================================
77
78 %%--------------------------------------------------------------------
79 %% @private
80 %% @doc
81 %% Initializes the server
82 %%
83 %% @spec init(Args) -> {ok, State} |
84 %% {ok, State, Timeout} |
85 %% ignore |
86 %% {stop, Reason}
87 %% @end
88 %%--------------------------------------------------------------------
89 -spec init([]) -> gen_server_init_result().
d004ab8 @jlouis Internalize the API of agner_server
jlouis authored
90
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
91 init([]) ->
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
92 {ok, #state{
93 }}.
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
94
95 %%--------------------------------------------------------------------
96 %% @private
97 %% @doc
98 %% Handling call messages
99 %%
100 %% @spec handle_call(Request, From, State) ->
101 %% {reply, Reply, State} |
102 %% {reply, Reply, State, Timeout} |
103 %% {noreply, State} |
104 %% {noreply, State, Timeout} |
105 %% {stop, Reason, Reply, State} |
106 %% {stop, Reason, State}
107 %% @end
108 %%--------------------------------------------------------------------
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
109 -type agner_call_spec() :: {spec, agner_package_name(), agner_package_version()}.
110 -type agner_call_spec_url() :: {spec_url, agner_package_name(), agner_package_version()}.
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
111 -type agner_call_index() :: index.
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
112 -type agner_call_fetch() :: {fetch, agner_package_name() | agner_spec(), agner_package_version(), directory()}.
113 -type agner_call_versions() :: {versions, agner_package_name()}.
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
114
978fb8b @yrashk Simplistic version naming scheme: @name for branches, the rest for tags.
yrashk authored
115 -spec handle_call(agner_call_spec(), gen_server_from(), gen_server_state()) -> gen_server_async_reply(agner_spec()|{error, bad_version}) ;
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
116 (agner_call_spec_url(), gen_server_from(), gen_server_state()) -> gen_server_async_reply(url()|{error, bad_version}) ;
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
117 (agner_call_index(), gen_server_from(), gen_server_state()) -> gen_server_async_reply(list(agner_package_name())) ;
2c928e9 @yrashk Added `versions' command
yrashk authored
118 (agner_call_fetch(), gen_server_from(), gen_server_state()) -> gen_server_async_reply(ok | {error, any()}) ;
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
119 (agner_call_versions(), gen_server_from(), gen_server_state()) -> gen_server_async_reply(list(agner_package_version()) | not_found_error()).
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
120
61c97b0 @yrashk Added modular indeces support
yrashk authored
121 handle_call({spec, Name, Version}, From, #state{}=State) ->
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
122 spawn_link(fun () ->
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
123 handle_spec(Name, Version, From, indices())
124 end),
125 {noreply, State};
126
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
127 handle_call({spec_url, Name, Version}, From, #state{}=State) ->
128 spawn_link(fun () ->
129 handle_spec_url(Name, Version, From, indices())
130 end),
131 {noreply, State};
132
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
133 handle_call(index, From, #state{}=State) ->
134 spawn_link(fun () ->
00404ec @yrashk listing packages should actually concatenate results from all indices
yrashk authored
135 handle_index(From, [], indices())
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
136 end),
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
137 {noreply, State};
138
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
139 handle_call({fetch, NameOrSpec, Version, Directory}, From, #state{}=State) ->
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
140 spawn_link(fun () ->
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
141 handle_fetch(NameOrSpec, Version, Directory, From)
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
142 end),
2c928e9 @yrashk Added `versions' command
yrashk authored
143 {noreply, State};
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
144
2c928e9 @yrashk Added `versions' command
yrashk authored
145 handle_call({versions, Name}, From, #state{}=State) ->
146 spawn_link(fun () ->
147 handle_versions(Name, From, indices())
148 end),
149 {noreply, State}.
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
150
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
151
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
152 %%--------------------------------------------------------------------
153 %% @private
154 %% @doc
155 %% Handling cast messages
156 %%
157 %% @spec handle_cast(Msg, State) -> {noreply, State} |
158 %% {noreply, State, Timeout} |
159 %% {stop, Reason, State}
160 %% @end
161 %%--------------------------------------------------------------------
162 handle_cast(_Msg, State) ->
163 {noreply, State}.
164
165 %%--------------------------------------------------------------------
166 %% @private
167 %% @doc
168 %% Handling all non call/cast messages
169 %%
170 %% @spec handle_info(Info, State) -> {noreply, State} |
171 %% {noreply, State, Timeout} |
172 %% {stop, Reason, State}
173 %% @end
174 %%--------------------------------------------------------------------
175
176 -spec handle_info(any(), gen_server_state()) ->
177 gen_server_handle_info_result().
178
179 handle_info(_, State) ->
180 {noreply, State}.
181
182 %%--------------------------------------------------------------------
183 %% @private
184 %% @doc
185 %% This function is called by a gen_server when it is about to
186 %% terminate. It should be the opposite of Module:init/1 and do any
187 %% necessary cleaning up. When it returns, the gen_server terminates
188 %% with Reason. The return value is ignored.
189 %%
190 %% @spec terminate(Reason, State) -> void()
191 %% @end
192 %%--------------------------------------------------------------------
193 terminate(_Reason, _State) ->
194 ok.
195
196 %%--------------------------------------------------------------------
197 %% @private
198 %% @doc
199 %% Convert process state when code is changed
200 %%
201 %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
202 %% @end
203 %%--------------------------------------------------------------------
204 code_change(_OldVsn, State, _Extra) ->
205 {ok, State}.
206
207 %%%===================================================================
208 %%% Internal functions
15e5a5f @yrashk Added more typespecs
yrashk authored
209 %%%===================================================================
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
210 -spec handle_spec(agner_package_name(), agner_package_version(), gen_server_from(), agner_indices()) -> any().
61c97b0 @yrashk Added modular indeces support
yrashk authored
211 handle_spec(_,_,From,[]) ->
212 gen_server:reply(From, {error, not_found});
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
213 handle_spec(Name, Version, From, [{Mod0, Params}|Rest]) ->
61c97b0 @yrashk Added modular indeces support
yrashk authored
214 Mod = index_module(Mod0),
b8b3e05 @yrashk Added agner_index:exists/2 to the specification and agner_github:exis…
yrashk authored
215 case Mod:exists(Params, Name) of
216 true ->
217 case Mod:spec(Params, Name, Version) of
218 {error, not_found} ->
219 handle_spec(Name, Version, From, Rest);
220 Data ->
221 gen_server:reply(From, Data)
222 end;
223 false ->
224 handle_spec(Name, Version, From, Rest)
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
225 end.
61c97b0 @yrashk Added modular indeces support
yrashk authored
226
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
227 -spec handle_spec_url(agner_package_name(), agner_package_version(), gen_server_from(), agner_indices()) -> any().
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
228 handle_spec_url(_,_,From,[]) ->
229 gen_server:reply(From, {error, not_found});
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
230 handle_spec_url(Name, Version, From, [{Mod0, Params}|Rest]) ->
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
231 Mod = index_module(Mod0),
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
232 case sha1(Mod, Params, Name, Version) of
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
233 SHA1 when is_list(SHA1) ->
b8b3e05 @yrashk Added agner_index:exists/2 to the specification and agner_github:exis…
yrashk authored
234 case Mod:exists(Params, Name) of
235 true ->
236 case Mod:spec_url(Params, Name, SHA1) of
237 {error, not_found} ->
238 handle_spec_url(Name, Version, From, Rest);
239 URL ->
240 gen_server:reply(From, URL)
241 end;
242 false ->
243 handle_spec_url(Name, Version, From, Rest)
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
244 end;
245 _ ->
246 gen_server:reply(From, {error, bad_version})
247 end.
248
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
249 -spec handle_index(gen_server_from(), list(agner_package_name()), list(tuple())) -> any().
00404ec @yrashk listing packages should actually concatenate results from all indices
yrashk authored
250 handle_index(From, Acc, []) ->
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
251 Repos = lists:reverse(Acc),
252 RepoNames = lists:map(fun ({Name, _}) -> Name end, Repos),
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
253 lists:foreach(fun (Name) ->
254 {ok, Pid} = agner_repo_server:create(Name, {flavour, "master"}),
255 agner_repo_server:set_pushed_at(Pid, binary_to_list(proplists:get_value(Name, Repos)))
256 end, RepoNames),
78f1f06 @yrashk Output package list as soon it is fetched
yrashk authored
257 gen_server:reply(From, lists:usort(RepoNames));
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
258 handle_index(From, Acc, [{Mod0, Params}|Rest]) ->
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
259 Mod = index_module(Mod0),
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
260 case Mod:repositories(Params) of
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
261 {error, not_found} ->
00404ec @yrashk listing packages should actually concatenate results from all indices
yrashk authored
262 handle_index(From, Acc, Rest);
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
263 Repos ->
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
264 handle_index(From, lists:map(fun (Repo) -> indexize(Mod0, Params, Repo) end, Repos) ++ Acc, Rest)
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
265 end.
266
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
267 -spec handle_fetch(agner_package_name() | agner_spec(), agner_package_version(), directory(), gen_server_from()) -> any().
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
268 handle_fetch(NameOrSpec, Version, Directory, From) ->
269 case io_lib:printable_list(NameOrSpec) of
270 true ->
271 case agner:spec(NameOrSpec, Version) of
272 {error, _} = Error ->
273 gen_server:reply(From, Error);
274 Spec ->
149e6dd @yrashk Store specification in fetched repositories
yrashk authored
275 agner_download:fetch(Spec, Directory),
d87929f @yrashk Added -s/--spec-file option to fetch, spec & install commands (allows…
yrashk authored
276 gen_server:reply(From, ok)
277 end;
278 false -> %% it is a spec
149e6dd @yrashk Store specification in fetched repositories
yrashk authored
279 agner_download:fetch(NameOrSpec, Directory),
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
280 gen_server:reply(From, ok)
281 end.
282
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
283 -spec handle_versions(agner_package_name(), gen_server_from(), agner_indices()) -> any().
2c928e9 @yrashk Added `versions' command
yrashk authored
284 handle_versions(_,From,[]) ->
285 gen_server:reply(From, {error, not_found});
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
286 handle_versions(Name, From, [{Mod0, Params}|Rest]) ->
2c928e9 @yrashk Added `versions' command
yrashk authored
287 Mod = index_module(Mod0),
b8b3e05 @yrashk Added agner_index:exists/2 to the specification and agner_github:exis…
yrashk authored
288 case Mod:exists(Params, Name) of
289 true ->
290 case Mod:repository(Params, Name) of
291 {error, not_found} ->
292 handle_versions(Name, From, Rest);
293 _ ->
294 Branches = lists:map(fun
295 ({[$%|_],_}) -> undefined;
296 ({"gh-pages",_}) -> undefined;
297 ({Branch, _}) -> {flavour, Branch} end,
298 Mod:branches(Params, Name)),
299 Tags = lists:map(fun ({[$%|_],_}) -> undefined;
300 ({Tag, _}) -> {release, Tag} end,
301 Mod:tags(Params, Name)),
302 gen_server:reply(From, lists:filter(fun (undefined) -> false; (_) -> true end, Branches ++ Tags))
303 end;
304 false ->
305 handle_versions(Name, From, Rest)
306 end.
2c928e9 @yrashk Added `versions' command
yrashk authored
307
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
308 -spec sha1(agner_index(), agner_account(), agner_package_name(), agner_package_version()) -> sha1().
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
309
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
310 sha1(Mod, Params, Name, Version) ->
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
311 case Version of
4d7ba64 @yrashk Internal change: finally renamed branch versions to flavours and tag …
yrashk authored
312 {flavour, Branch} ->
baf7e9f @yrashk Avoid making too many GitHub API calls: 1) don't resolve branches 2) …
yrashk authored
313 Branch;
4d7ba64 @yrashk Internal change: finally renamed branch versions to flavours and tag …
yrashk authored
314 {release, Tag} ->
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
315 Tags = Mod:tags(Params, Name),
5688d6a @yrashk Added atleast: version prefix
yrashk authored
316 proplists:get_value(Tag, Tags);
317 no_such_version ->
318 no_such_version
0cdd671 @yrashk Initial simplistic fetching functionality
yrashk authored
319 end.
320
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
321
f6b4247 @yrashk Index name -> access module matching is now defined using application…
yrashk authored
322 index_module(T) ->
323 case application:get_env(index_modules) of
324 {ok, Modules} ->
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
325 proplists:get_value(T, Modules);
f6b4247 @yrashk Index name -> access module matching is now defined using application…
yrashk authored
326 _ ->
327 T
328 end.
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
329
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
330 indexize(github, "agner", Name) ->
00404ec @yrashk listing packages should actually concatenate results from all indices
yrashk authored
331 Name;
5239887 @ferd unparametrized agner_index, agner_github and agner_server
ferd authored
332 indexize(github, Account, Name) ->
e179265 @yrashk Typo fix
yrashk authored
333 Account ++ "/" ++ Name.
00404ec @yrashk listing packages should actually concatenate results from all indices
yrashk authored
334
453d4cc @yrashk Added agner:index/0 and "list" command for the command line utility
yrashk authored
335 indices() ->
336 case application:get_env(indices) of
337 {ok, Val} ->
338 Val;
339 undefined ->
340 []
341 end.
Something went wrong with that request. Please try again.