Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 232 lines (190 sloc) 8.537 kB
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
1 -module(agner_repo_server).
2 -include_lib("typespecs/include/typespecs.hrl").
3 -include_lib("agner.hrl").
4 -behaviour(gen_server).
5
6 %% API
7 -export([create/2, start_link/2]).
8 -export([set_pushed_at/2, pushed_at/1, clone/2, file/2]).
9
10 %% gen_server callbacks
11 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
12 terminate/2, code_change/3]).
13
14 -define(SERVER, ?MODULE).
15
16
17 -type pushed_at() :: string() | undefined.
18
19 -record(state, {
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
20 name :: agner_package_name() | undefined,
21 version :: agner_package_version() | undefined,
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
22 pushed_at :: pushed_at(),
23 directory :: directory() | undefined
24 }).
25
26 -type gen_server_state() :: #state{}.
27
28 %%%===================================================================
29 %%% API
30 %%%===================================================================
31
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
32 -spec create(agner_package_name(), agner_package_version()) -> {ok, pid()}.
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
33
34 create(Name, Version) ->
fb9af35 @yrashk Moved out gproc process caching to agner_repo_server:create/2
yrashk authored
35 case gproc:lookup_local_name({?SERVER, Name, Version}) of
36 Pid when is_pid(Pid) ->
37 {ok, Pid};
38 _ ->
39 supervisor:start_child(agner_repo_server_sup, [Name, Version])
40 end.
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
41
42 %%--------------------------------------------------------------------
43 %% @doc
44 %% Starts the server
45 %%
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
46 %% @spec start_link(agner_package_name(), agner_package_version()) -> {ok, Pid} | ignore | {error, Error}
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
47 %% @end
48 %%--------------------------------------------------------------------
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
49 -spec start_link(agner_package_name(), agner_package_version()) -> {ok, pid()} | ignore | {error, term()}.
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
50
51 start_link(Name, Version) ->
fb9af35 @yrashk Moved out gproc process caching to agner_repo_server:create/2
yrashk authored
52 gen_server:start_link(?MODULE, {Name, Version}, []).
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
53
54 -spec set_pushed_at(pid(), pushed_at()) -> ok.
55
56 set_pushed_at(Pid, PushedAt) ->
57 gen_server:cast(Pid, {set_pushed_at, PushedAt}).
58
59 -spec pushed_at(pid()) -> pushed_at().
60
61 pushed_at(Pid) ->
62 gen_server:call(Pid, pushed_at).
63
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
64 -type repo_url_function() :: fun((agner_package_name()) -> url()).
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
65
66 -spec clone(pid(), repo_url_function()) -> ok.
67
68 clone(Pid, Fun) ->
9cdf0be @yrashk agner_repo_server:clone/2 shouldn't timeout
yrashk authored
69 gen_server:call(Pid, {clone, Fun}, infinity).
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
70
25eb3d6 @yrashk Fixed a bug in agner_repo_server:file/2 implementation when it didn't…
yrashk authored
71 -spec file(pid(), file()) -> file() | not_found_error() | {error, not_cloned}.
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
72
73 file(Pid, Filename) ->
74 gen_server:call(Pid, {file, Filename}).
75
76 %%%===================================================================
77 %%% gen_server callbacks
78 %%%===================================================================
79
80 %%--------------------------------------------------------------------
81 %% @private
82 %% @doc
83 %% Initializes the server
84 %%
85 %% @spec init(Args) -> {ok, State} |
86 %% {ok, State, Timeout} |
87 %% ignore |
88 %% {stop, Reason}
89 %% @end
90 %%--------------------------------------------------------------------
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
91 -spec init({agner_package_name(), agner_package_version()}) -> gen_server_init_result().
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
92
93 init({Name, Version}) ->
b486690 @yrashk Trap exit in agner_repo_server so we can actually cleanup checked out…
yrashk authored
94 process_flag(trap_exit, true),
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
95 gproc:add_local_name({?SERVER, Name, Version}),
96 {ok, #state{
97 name = Name,
98 version = Version
99 }}.
100
101 %%--------------------------------------------------------------------
102 %% @private
103 %% @doc
104 %% Handling call messages
105 %%
106 %% @spec handle_call(Request, From, State) ->
107 %% {reply, Reply, State} |
108 %% {reply, Reply, State, Timeout} |
109 %% {noreply, State} |
110 %% {noreply, State, Timeout} |
111 %% {stop, Reason, Reply, State} |
112 %% {stop, Reason, State}
113 %% @end
114 %%--------------------------------------------------------------------
115 -type pushed_at_call() :: pushed_at().
116 -type clone_call() :: {clone, repo_url_function()}.
117 -type file_call() :: {file, file()}.
118
119 -spec handle_call(pushed_at_call(), gen_server_from(), gen_server_state()) ->
120 gen_server_handle_call_result(pushed_at());
121 (clone_call(), gen_server_from(), gen_server_state()) ->
122 gen_server_handle_call_result(ok);
123 (file_call(), gen_server_from(), gen_server_state()) ->
25eb3d6 @yrashk Fixed a bug in agner_repo_server:file/2 implementation when it didn't…
yrashk authored
124 gen_server_handle_call_result(file() | not_found_error() | {error, not_cloned}).
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
125
126 handle_call(pushed_at, _From, #state{ pushed_at = PushedAt } = State) ->
127 {reply, PushedAt, State};
128
129 handle_call({clone, Fun}, _From, #state{ directory = undefined, name = Name, version = Version } = State) ->
130 Directory = test_server:temp_name("/tmp/agner"),
131 RepoName = apply(Fun,[Name]),
132 ClonePort = agner_download:git(["clone", "-q", RepoName, Directory]),
133 Result = agner_download:process_port(ClonePort,
134 fun () ->
135 PortCheckout = agner_download:git(["checkout","-q",version_to_ref(Version)],
136 [{cd, Directory}]),
137 agner_download:process_port(PortCheckout, fun () ->
138 ok
56ffab6 @yrashk Fixed a bug that was preventing agner_repo_server:clone from catching…
yrashk authored
139 end)
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
140 end),
36799d9 @yrashk Fixed broken indices chaining
yrashk authored
141 case Result of
142 ok ->
143 {reply, ok, State#state{ directory = Directory }};
144 _ ->
145 {reply, Result, State}
146 end;
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
147
148 handle_call({clone, _Fun}, _From, #state{} = State) -> %% already cloned
149 {reply, ok, State};
150
25eb3d6 @yrashk Fixed a bug in agner_repo_server:file/2 implementation when it didn't…
yrashk authored
151 handle_call({file, Filename}, _From, #state{ directory = Directory} = State) when is_list(Directory) ->
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
152 F = filename:join(Directory, Filename),
153 case (filelib:is_dir(F) or filelib:is_file(F)) of
154 true ->
155 {reply, F, State};
156 false ->
157 {reply, {error, not_found}, State}
25eb3d6 @yrashk Fixed a bug in agner_repo_server:file/2 implementation when it didn't…
yrashk authored
158 end;
159
160 handle_call({file, _Filename}, _From, #state{ directory = undefined } = State) ->
161 {reply, {error, not_cloned}, State}.
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
162
163
164 %%--------------------------------------------------------------------
165 %% @private
166 %% @doc
167 %% Handling cast messages
168 %%
169 %% @spec handle_cast(Msg, State) -> {noreply, State} |
170 %% {noreply, State, Timeout} |
171 %% {stop, Reason, State}
172 %% @end
173 %%--------------------------------------------------------------------
174 -type set_pushed_at_cast() :: {set_pushed_at, pushed_at()}.
175
176 -spec handle_cast(set_pushed_at_cast(), gen_server_state()) -> gen_server_handle_cast_result().
177
178 handle_cast({set_pushed_at, PushedAt}, #state{}=State) ->
179 {noreply, State#state{ pushed_at = PushedAt} }.
180
181 %%--------------------------------------------------------------------
182 %% @private
183 %% @doc
184 %% Handling all non call/cast messages
185 %%
186 %% @spec handle_info(Info, State) -> {noreply, State} |
187 %% {noreply, State, Timeout} |
188 %% {stop, Reason, State}
189 %% @end
190 %%--------------------------------------------------------------------
191 handle_info(_Info, State) ->
192 {noreply, State}.
193
194 %%--------------------------------------------------------------------
195 %% @private
196 %% @doc
197 %% This function is called by a gen_server when it is about to
198 %% terminate. It should be the opposite of Module:init/1 and do any
199 %% necessary cleaning up. When it returns, the gen_server terminates
200 %% with Reason. The return value is ignored.
201 %%
202 %% @spec terminate(Reason, State) -> void()
203 %% @end
204 %%--------------------------------------------------------------------
205 terminate(_Reason, #state{ directory = Directory }) when is_list(Directory) ->
db2527c @yrashk agner_repo_servers cleanup after themselves properly now
yrashk authored
206 os:cmd("rm -rf " ++ Directory),
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
207 ok;
208 terminate(_Reason, _State) ->
209 ok.
210
211 %%--------------------------------------------------------------------
212 %% @private
213 %% @doc
214 %% Convert process state when code is changed
215 %%
216 %% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
217 %% @end
218 %%--------------------------------------------------------------------
219 code_change(_OldVsn, State, _Extra) ->
220 {ok, State}.
221
222 %%%===================================================================
223 %%% Internal functions
224 %%%===================================================================
fcde3b0 @yrashk Renamed agner_spec_name() and agner_spec_version() typespecs to agner…
yrashk authored
225 -spec version_to_ref(agner_package_version()) -> string().
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
226
227 version_to_ref({flavour, Branch}) ->
228 "origin/" ++ Branch;
229 version_to_ref({release, Tag}) ->
230 Tag.
231
Something went wrong with that request. Please try again.