Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 156 lines (134 sloc) 4.936 kb
44a5bb4 Jesper Louis Andersen Hint Emacs that the Tab Stop of the files are 4 spaces.
jlouis authored
1 %% -*- Mode: Erlang; tab-width: 4 -*-
3d5cf18 Yurii Rashkovskii Made agner_github a parametrized module
yrashk authored
2 -module(agner_github, [Account]).
61c97b0 Yurii Rashkovskii 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 Yurii Rashkovskii Added -b/--browser option that will open browser to show the specificati...
yrashk authored
11 spec/2,
12 spec_url/2
1aabca9 Yurii Rashkovskii Initial WIP, nothing to see yet
yrashk authored
13 ]).
14
61c97b0 Yurii Rashkovskii Added modular indeces support
yrashk authored
15 repositories() ->
38f928b Yurii Rashkovskii Apparently GitHub API or listing repositories paginates results, so we n...
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 Yurii Rashkovskii Added modular indeces support
yrashk authored
20 {error, _Reason} = Error ->
21 Error;
22 {struct, Object} ->
38f928b Yurii Rashkovskii Apparently GitHub API or listing repositories paginates results, so we n...
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 Yurii Rashkovskii Added modular indeces support
yrashk authored
38 end.
39
40 repository(Name) ->
1539dde Yurii Rashkovskii 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 Yurii Rashkovskii 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 Yurii Rashkovskii Initial WIP, nothing to see yet
yrashk authored
49
61c97b0 Yurii Rashkovskii Added modular indeces support
yrashk authored
50 tags(Name) ->
26b6f04 Yurii Rashkovskii Use https for github
yrashk authored
51 case request("https://github.com/api/v2/json/repos/show/" ++ proper_repo_name(Name) ++ "/tags") of
61c97b0 Yurii Rashkovskii 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 Yurii Rashkovskii Use https for github
yrashk authored
62 case request("https://github.com/api/v2/json/repos/show/" ++ proper_repo_name(Name) ++ "/branches") of
61c97b0 Yurii Rashkovskii 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 Yurii Rashkovskii Initial WIP, nothing to see yet
yrashk authored
72
7ee519f Yurii Rashkovskii 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 Yurii Rashkovskii Implemented some aggressive caching and got rid of another GitHub API ra...
yrashk authored
76 At when is_list(At) ->
77 DotDir = filename:join(os:getenv("HOME"),".agner"),
78 filelib:ensure_dir(DotDir ++ "/"),
7ee519f Yurii Rashkovskii 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 Yurii Rashkovskii Implemented some aggressive caching and got rid of another GitHub API ra...
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 Yurii Rashkovskii Extracted agner_repo_server
yrashk authored
92 Result = spec_1(RepoServer, TmpFile),
77ad16b Yurii Rashkovskii Implemented some aggressive caching and got rid of another GitHub API ra...
yrashk authored
93 file:delete(TmpFile),
94 Result
95 end.
96
7ee519f Yurii Rashkovskii Extracted agner_repo_server
yrashk authored
97 spec_1(RepoServer, AtFilename) ->
77ad16b Yurii Rashkovskii Implemented some aggressive caching and got rid of another GitHub API ra...
yrashk authored
98 case file:read_file_info(AtFilename) of
99 {error, enoent} ->
7ee519f Yurii Rashkovskii 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 Yurii Rashkovskii Implemented some aggressive caching and got rid of another GitHub API ra...
yrashk authored
106 {ok, _} ->
107 {ok, S} = file:consult(AtFilename),
108 S
109 end.
110
7e7089d Yurii Rashkovskii Added -b/--browser option that will open browser to show the specificati...
yrashk authored
111 spec_url(Name, SHA1) ->
112 "https://github.com/" ++ proper_repo_name(Name) ++ "/blob/" ++ SHA1 ++ "/agner.config".
1aabca9 Yurii Rashkovskii Initial WIP, nothing to see yet
yrashk authored
113
114 %%%
115
1539dde Yurii Rashkovskii 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 Yurii Rashkovskii 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 Yurii Rashkovskii 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 Yurii Rashkovskii Added a clause for GitHub's 403 status code (normally used when API rate...
yrashk authored
142 {error, not_found};
143 parse_response({ok, {{"HTTP/1.1",403,_}, _Headers, _Body}}) ->
144 {error, github_rate_limit_exceeded}.
61c97b0 Yurii Rashkovskii 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.