Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 156 lines (134 sloc) 4.936 kB
44a5bb4 @jlouis Hint Emacs that the Tab Stop of the files are 4 spaces.
jlouis authored
1 %% -*- Mode: Erlang; tab-width: 4 -*-
3d5cf18 @yrashk Made agner_github a parametrized module
yrashk authored
2 -module(agner_github, [Account]).
61c97b0 @yrashk Added modular indeces support
yrashk authored
3 -behaviour(agner_index).
4 -include_lib("agner.hrl").
5 -include_lib("agner_index.hrl").
6
7 -export([repositories/0,
8 repository/1,
9 tags/1,
10 branches/1,
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
11 spec/2,
12 spec_url/2
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
13 ]).
14
61c97b0 @yrashk Added modular indeces support
yrashk authored
15 repositories() ->
38f928b @yrashk Apparently GitHub API or listing repositories paginates results, so w…
yrashk authored
16 repositories(1).
17
18 repositories(Page) ->
19 case request("https://github.com/api/v2/json/repos/show/" ++ Account ++ "?page=" ++ integer_to_list(Page)) of
61c97b0 @yrashk Added modular indeces support
yrashk authored
20 {error, _Reason} = Error ->
21 Error;
22 {struct, Object} ->
38f928b @yrashk Apparently GitHub API or listing repositories paginates results, so w…
yrashk authored
23 case proplists:get_value(<<"repositories">>, Object) of
24 [] ->
25 [];
26 Repositories ->
27 Repos = lists:filter(fun ({invalid,_}) ->
28 false;
29 (_) ->
30 true
31 end,
32 lists:map(fun ({struct, RepObject}) ->
33 {repo_name(proplists:get_value(<<"name">>, RepObject)),
34 proplists:get_value(<<"pushed_at">>, RepObject)}
35 end, Repositories)),
36 Repos ++ repositories(Page + 1)
37 end
61c97b0 @yrashk Added modular indeces support
yrashk authored
38 end.
39
40 repository(Name) ->
1539dde @yrashk Allow using github accounts other than 'agner'
yrashk authored
41 case request("https://github.com/api/v2/json/repos/show/" ++ proper_repo_name(Name)) of
61c97b0 @yrashk Added modular indeces support
yrashk authored
42 {error, _Reason} = Error ->
43 Error;
44 {struct, Object} ->
45 {struct, Repo} = proplists:get_value(<<"repository">>, Object),
46 Repo
47 end.
48
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
49
61c97b0 @yrashk Added modular indeces support
yrashk authored
50 tags(Name) ->
26b6f04 @yrashk Use https for github
yrashk authored
51 case request("https://github.com/api/v2/json/repos/show/" ++ proper_repo_name(Name) ++ "/tags") of
61c97b0 @yrashk Added modular indeces support
yrashk authored
52 {struct, Object} ->
53 {struct, Tags} = proplists:get_value(<<"tags">>, Object),
54 lists:map(fun({Tag, SHA1}) ->
55 {binary_to_list(Tag),
56 binary_to_list(SHA1)}
57 end, Tags)
58 end.
59
60
61 branches(Name) ->
26b6f04 @yrashk Use https for github
yrashk authored
62 case request("https://github.com/api/v2/json/repos/show/" ++ proper_repo_name(Name) ++ "/branches") of
61c97b0 @yrashk Added modular indeces support
yrashk authored
63 {error, _Reason} = Error ->
64 Error;
65 {struct, Object} ->
66 {struct, Branches} = proplists:get_value(<<"branches">>, Object),
67 lists:map(fun({Branch, SHA1}) ->
68 {binary_to_list(Branch),
69 binary_to_list(SHA1)}
70 end, Branches)
71 end.
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
72
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
73 spec(Name, Version) ->
74 {ok, RepoServer} = agner_repo_server:create(Name, Version),
75 case agner_repo_server:pushed_at(RepoServer) of
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
76 At when is_list(At) ->
77 DotDir = filename:join(os:getenv("HOME"),".agner"),
78 filelib:ensure_dir(DotDir ++ "/"),
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
79 AtFilename = filename:join([DotDir, "cache." ++ Name ++ integer_to_list(erlang:phash2(Version)) ++
80 lists:map(fun ($/) ->
81 $_;
82 ($\s) ->
83 $_;
84 (C) ->
85 C
86 end, At)]),
87 spec_1(RepoServer, AtFilename);
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
88 undefined ->
89 {A,B,C} = now(),
90 N = node(),
91 TmpFile = lists:flatten(io_lib:format("/tmp/agner-~p-~p.~p.~p",[N,A,B,C])),
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
92 Result = spec_1(RepoServer, TmpFile),
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
93 file:delete(TmpFile),
94 Result
95 end.
96
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
97 spec_1(RepoServer, AtFilename) ->
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
98 case file:read_file_info(AtFilename) of
99 {error, enoent} ->
7ee519f @yrashk Extracted agner_repo_server
yrashk authored
100 ok = agner_repo_server:clone(RepoServer, fun (Name) -> "git://github.com/" ++ proper_repo_name(Name) ++ ".git" end),
101
102 Config = agner_repo_server:file(RepoServer, "agner.config"),
103 {ok, S} = file:consult(Config),
104 {ok, _} = file:copy(Config, AtFilename),
105 S;
77ad16b @yrashk Implemented some aggressive caching and got rid of another GitHub API…
yrashk authored
106 {ok, _} ->
107 {ok, S} = file:consult(AtFilename),
108 S
109 end.
110
7e7089d @yrashk Added -b/--browser option that will open browser to show the specific…
yrashk authored
111 spec_url(Name, SHA1) ->
112 "https://github.com/" ++ proper_repo_name(Name) ++ "/blob/" ++ SHA1 ++ "/agner.config".
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
113
114 %%%
115
1539dde @yrashk Allow using github accounts other than 'agner'
yrashk authored
116 proper_repo_name(Name) ->
117 case string:tokens(Name,"/") of
118 [_, _]=L ->
119 string:join(L,"/") ++ ".agner";
120 [Name] ->
121 string:join([Account, Name],"/") ++ ".agner"
122 end.
123
124 %%%
125
1aabca9 @yrashk Initial WIP, nothing to see yet
yrashk authored
126 request(URL) ->
127 parse_response(httpc_request(URL)).
128
129 httpc_request(URL) ->
130 httpc_request_1(URL,[]).
131
132 httpc_request_1(URL, Opts) ->
133 httpc:request(get,{URL,
134 []},
135 [{timeout, 60000}],
136 Opts,
137 agner).
61c97b0 @yrashk Added modular indeces support
yrashk authored
138
139 parse_response({ok, {{"HTTP/1.1",200,_},_Headers,Body}}) ->
140 mochijson2:decode(Body);
141 parse_response({ok, {{"HTTP/1.1",404,_},_Headers,_Body}}) ->
4877e63 @yrashk Added a clause for GitHub's 403 status code (normally used when API r…
yrashk authored
142 {error, not_found};
143 parse_response({ok, {{"HTTP/1.1",403,_}, _Headers, _Body}}) ->
144 {error, github_rate_limit_exceeded}.
61c97b0 @yrashk Added modular indeces support
yrashk authored
145 %%%
146
147 repo_name(B) when is_binary(B) ->
148 S = binary_to_list(B),
149 case string:tokens(S,".") of
150 [Name,"agner"] ->
151 Name;
152 _ ->
153 invalid
154 end.
155
Something went wrong with that request. Please try again.