capricorn 0.2.25 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/LICENSE +19 -0
  2. data/README.md +1 -0
  3. data/bin/capricorn-app-scaffolder +27 -0
  4. data/bin/capricorn-gem-spec +33 -0
  5. data/bin/capricornctl +12 -0
  6. data/bin/capricornd +31 -0
  7. data/erlang/lib/bert/doc/overview.edoc +4 -0
  8. data/erlang/lib/bert/ebin/bert.app +9 -0
  9. data/erlang/lib/bert/rebar.config +3 -0
  10. data/erlang/lib/bert/src/bert.erl +69 -0
  11. data/erlang/lib/bertio/doc/overview.edoc +4 -0
  12. data/erlang/lib/bertio/ebin/bertio.app +9 -0
  13. data/erlang/lib/bertio/rebar.config +3 -0
  14. data/erlang/lib/bertio/src/bertio.erl +28 -0
  15. data/erlang/lib/bertrpc/doc/overview.edoc +4 -0
  16. data/erlang/lib/bertrpc/ebin/bertrpc.app +12 -0
  17. data/erlang/lib/bertrpc/include/bertrpc.hrl +1 -0
  18. data/erlang/lib/bertrpc/rebar.config +5 -0
  19. data/erlang/lib/bertrpc/src/bertrpc.erl +471 -0
  20. data/erlang/lib/bertrpc/src/bertrpc_hello_world.erl +148 -0
  21. data/erlang/lib/bertrpc/src/fd_tcp.erl +376 -0
  22. data/erlang/lib/capricorn/doc/overview.edoc +4 -0
  23. data/erlang/lib/capricorn/ebin/capricorn.app +56 -0
  24. data/erlang/lib/capricorn/include/capricorn.hrl +76 -0
  25. data/erlang/lib/capricorn/rebar.config +3 -0
  26. data/erlang/lib/capricorn/src/cap_application.erl +170 -0
  27. data/erlang/lib/capricorn/src/cap_cluster.erl +121 -0
  28. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +422 -0
  29. data/erlang/lib/capricorn/src/cap_config.erl +25 -0
  30. data/erlang/lib/capricorn/src/cap_dets_updater.erl +26 -0
  31. data/erlang/lib/capricorn/src/cap_event_sup.erl +35 -0
  32. data/erlang/lib/capricorn/src/cap_events.erl +24 -0
  33. data/erlang/lib/capricorn/src/cap_external_api.erl +87 -0
  34. data/erlang/lib/capricorn/src/cap_external_apps_api.erl +125 -0
  35. data/erlang/lib/capricorn/src/cap_external_gems_api.erl +85 -0
  36. data/erlang/lib/capricorn/src/cap_external_machines_api.erl +18 -0
  37. data/erlang/lib/capricorn/src/cap_gem_utils.erl +111 -0
  38. data/erlang/lib/capricorn/src/cap_internal_api.erl +69 -0
  39. data/erlang/lib/capricorn/src/cap_internal_apps_api.erl +38 -0
  40. data/erlang/lib/capricorn/src/cap_log.erl +113 -0
  41. data/erlang/lib/capricorn/src/cap_machine.erl +338 -0
  42. data/erlang/lib/capricorn/src/cap_machine_apps.erl +410 -0
  43. data/erlang/lib/capricorn/src/cap_machine_apps_sup.erl +57 -0
  44. data/erlang/lib/capricorn/src/cap_sup.erl +200 -0
  45. data/erlang/lib/capricorn/src/cap_util.erl +278 -0
  46. data/erlang/lib/capricorn/src/capricorn.erl +45 -0
  47. data/erlang/lib/capricorn/src/capricorn_app.erl +36 -0
  48. data/erlang/lib/emq/ebin/emq.app +17 -0
  49. data/erlang/lib/emq/src/emq.erl +261 -0
  50. data/erlang/lib/emq/src/emq_app.erl +11 -0
  51. data/erlang/lib/emq/src/emq_pool.erl +178 -0
  52. data/erlang/lib/emq/src/emq_queue.erl +332 -0
  53. data/erlang/lib/emq/src/emq_status.erl +148 -0
  54. data/erlang/lib/emq/src/emq_sup.erl +132 -0
  55. data/erlang/lib/gcd/ebin/gcd.app +18 -0
  56. data/erlang/lib/gcd/include/gcd.hrl +5 -0
  57. data/erlang/lib/gcd/rebar.config +3 -0
  58. data/erlang/lib/gcd/src/gcd.erl +51 -0
  59. data/erlang/lib/gcd/src/gcd_app.erl +13 -0
  60. data/erlang/lib/gcd/src/gcd_event.erl +39 -0
  61. data/erlang/lib/gcd/src/gcd_server.erl +30 -0
  62. data/erlang/lib/gcd/src/gcd_srv.erl +186 -0
  63. data/erlang/lib/gcd/src/gcd_sup.erl +18 -0
  64. data/erlang/rebar +0 -0
  65. data/erlang/rebar.config +9 -0
  66. data/erlang/rel/overlay/bin/capricornd +146 -0
  67. data/erlang/rel/overlay/erts-vsn/bin/erl +34 -0
  68. data/erlang/rel/overlay/erts-vsn/bin/nodetool +80 -0
  69. data/erlang/rel/overlay/etc/capricorn/app.config +59 -0
  70. data/erlang/rel/overlay/etc/capricorn/cluster-vm.args +21 -0
  71. data/erlang/rel/overlay/etc/capricorn/machine-vm.args +21 -0
  72. data/erlang/rel/reltool.config +43 -0
  73. data/ext/Makefile +2 -0
  74. data/ext/extconf.rb +1 -0
  75. data/lib/capricorn-client.rb +86 -0
  76. data/lib/capricorn-client/cli/applications.rb +256 -0
  77. data/lib/capricorn-client/cli/gems.rb +57 -0
  78. data/lib/capricorn-client/cli/machines.rb +9 -0
  79. data/lib/capricorn-client/helpers.rb +62 -0
  80. data/lib/capricorn.rb +5 -99
  81. data/lib/capricorn/driver.rb +86 -0
  82. data/lib/capricorn/recipes/apache-debian.rb +112 -0
  83. data/lib/capricorn/recipes/centos-plesk.rb +162 -0
  84. data/lib/capricorn/recipes/macports.rb +54 -0
  85. data/lib/capricorn/system_context.rb +49 -0
  86. data/lib/capricorn/version.rb +5 -0
  87. metadata +233 -74
  88. data/app_generators/engine/engine_generator.rb +0 -40
  89. data/app_generators/engine/templates/Gmfile +0 -20
  90. data/app_generators/engine/templates/MIT-LICENSE.txt +0 -20
  91. data/app_generators/engine/templates/README.rdoc +0 -7
  92. data/app_generators/engine/templates/config/initializers/rails_init.rb +0 -1
  93. data/app_generators/engine/templates/config/routes.rb +0 -2
  94. data/app_generators/engine/templates/gitignore +0 -9
  95. data/app_generators/engine/templates/init.rb +0 -1
  96. data/app_generators/engine/templates/lib/engine.rb +0 -4
  97. data/app_generators/engine/templates/rails/init.rb +0 -1
  98. data/app_generators/engine/templates/tasks/engine_tasks.rake +0 -4
  99. data/bin/capricorn +0 -20
  100. data/lib/capricorn/actor.rb +0 -23
  101. data/lib/capricorn/actor/actions.rb +0 -76
  102. data/lib/capricorn/actors/apache_actor.rb +0 -56
  103. data/lib/capricorn/actors/base_actor.rb +0 -335
  104. data/lib/capricorn/actors/host_file_actor.rb +0 -77
  105. data/lib/capricorn/actors/mysql_actor.rb +0 -20
  106. data/lib/capricorn/actors/passenger_actor.rb +0 -28
  107. data/lib/capricorn/actors/plesk_actor.rb +0 -228
  108. data/lib/capricorn/actors/sqlite3_actor.rb +0 -44
  109. data/lib/capricorn/app_runner.rb +0 -108
  110. data/lib/capricorn/apps/dev.rb +0 -15
  111. data/lib/capricorn/apps/engines.rb +0 -33
  112. data/lib/capricorn/apps/jobs.rb +0 -35
  113. data/lib/capricorn/apps/satellite.rb +0 -68
  114. data/lib/capricorn/apps/server.rb +0 -73
  115. data/lib/capricorn/client.rb +0 -48
  116. data/lib/capricorn/client/auth_token.rb +0 -98
  117. data/lib/capricorn/daemon.rb +0 -81
  118. data/lib/capricorn/exception_handler.rb +0 -79
  119. data/lib/capricorn/extentions/rubygems_plugin.rb +0 -27
  120. data/lib/capricorn/extentions/thor_extentions.rb +0 -32
  121. data/lib/capricorn/job_queue.rb +0 -203
  122. data/lib/capricorn/satellite.rb +0 -52
  123. data/lib/capricorn/satellite/actions.rb +0 -55
  124. data/lib/capricorn/satellite/dependency_loader.rb +0 -82
  125. data/lib/capricorn/satellite/persistence.rb +0 -50
  126. data/lib/capricorn/server.rb +0 -144
  127. data/lib/capricorn/server/daemon.rb +0 -83
  128. data/lib/capricorn/server/proxy.rb +0 -25
  129. data/lib/capricorn/server/security.rb +0 -120
  130. data/lib/capricorn/system.rb +0 -218
  131. data/lib/capricorn/system/config.rb +0 -49
  132. data/lib/capricorn/system/helper.rb +0 -21
  133. data/lib/capricorn/system/options.rb +0 -79
  134. data/lib/capricorn/system/process_user.rb +0 -73
  135. data/lib/capricorn/system/satellites.rb +0 -44
  136. data/lib/capricorn/system/shell.rb +0 -80
  137. data/lib/rubygems_plugin.rb +0 -1
  138. data/spec/actor/actions_spec.rb +0 -13
  139. data/spec/spec_helper.rb +0 -1
@@ -0,0 +1,25 @@
1
+ -module(cap_config).
2
+ -include("capricorn.hrl").
3
+
4
+
5
+
6
+ -export([all/0, get/1, get/2, get/3]).
7
+
8
+
9
+
10
+ all() ->
11
+ application:get_all_env(capricorn) ++ init:get_arguments().
12
+
13
+
14
+
15
+ get(Section) ->
16
+ proplists:get_value(Section, cap_config:all(), []).
17
+
18
+ get(Section, Key) ->
19
+ cap_config:get(Section, Key, undefined).
20
+
21
+ get(Section, Key, Default) ->
22
+ SectionValues = cap_config:get(Section),
23
+ proplists:get_value(Key, SectionValues, Default).
24
+
25
+
@@ -0,0 +1,26 @@
1
+ -module(cap_dets_updater).
2
+
3
+ -export([update/2]).
4
+
5
+ update(Table, Fun) ->
6
+ NewTerms = dets:foldl(fun(Term, Acc) ->
7
+ update_members([Term], Fun, Acc)
8
+ end, [], Table),
9
+ dets:delete_all_objects(Table),
10
+ dets:insert(Table, NewTerms),
11
+ ok.
12
+
13
+ update_members([], _Fun, Acc) -> Acc;
14
+ update_members([OldTerm|Rest], Fun, Acc) ->
15
+ case Fun(OldTerm) of
16
+ ok ->
17
+ update_members(Rest, Fun, [OldTerm|Acc]);
18
+ remove ->
19
+ update_members(Rest, Fun, Acc);
20
+ {update, Terms} when is_list(Terms) ->
21
+ update_members(Terms++Rest, Fun, Acc);
22
+ {update, Term} when is_tuple(Term) ->
23
+ update_members([Term|Rest], Fun, Acc);
24
+ Else ->
25
+ erlang:error({badarg, Else})
26
+ end.
@@ -0,0 +1,35 @@
1
+ -module(cap_event_sup).
2
+ -behaviour(gen_server).
3
+
4
+ -include("capricorn.hrl").
5
+
6
+ -export([start_link/3,start_link/4, stop/1]).
7
+ -export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2,code_change/3]).
8
+
9
+ start_link(EventMgr, EventHandler, Args) ->
10
+ gen_server:start_link(cap_event_sup, {EventMgr, EventHandler, Args}, []).
11
+
12
+ start_link(ServerName, EventMgr, EventHandler, Args) ->
13
+ gen_server:start_link(ServerName, cap_event_sup, {EventMgr, EventHandler, Args}, []).
14
+
15
+ stop(Pid) ->
16
+ gen_server:cast(Pid, stop).
17
+
18
+ init({EventMgr, EventHandler, Args}) ->
19
+ ok = gen_event:add_sup_handler(EventMgr, EventHandler, Args),
20
+ {ok, {EventMgr, EventHandler}}.
21
+
22
+ terminate(_Reason, _State) ->
23
+ ok.
24
+
25
+ handle_call(_Whatever, _From, State) ->
26
+ {ok, State}.
27
+
28
+ handle_cast(stop, State) ->
29
+ {stop, normal, State}.
30
+
31
+ handle_info({gen_event_EXIT, _Handler, Reason}, State) ->
32
+ {stop, Reason, State}.
33
+
34
+ code_change(_OldVsn, State, _Extra) ->
35
+ {ok, State}.
@@ -0,0 +1,24 @@
1
+ -module(cap_events).
2
+
3
+
4
+ -export([start_link/0]).
5
+ -export([notify/1, notify/2]).
6
+
7
+
8
+ start_link() ->
9
+ gen_event:start_link({local, ?MODULE}).
10
+
11
+
12
+ notify(Msg) ->
13
+ gen_event:notify(?MODULE, Msg).
14
+
15
+
16
+ notify(Node, Msg) when is_atom(Node) ->
17
+ notify([Node], Msg);
18
+
19
+ notify([Node|Rest], Msg) ->
20
+ gen_event:notify({?MODULE, Node}, Msg),
21
+ notify(Rest, Msg);
22
+
23
+ notify([], _Msg) ->
24
+ ok.
@@ -0,0 +1,87 @@
1
+ -module(cap_external_api).
2
+ -behaviour(bertrpc).
3
+
4
+
5
+
6
+ -export([start_link/1]).
7
+ -export([init/1, handle_call/3, handle_cast/2,
8
+ handle_info/2, terminate/2, code_change/3]).
9
+
10
+
11
+
12
+ -record(state, {
13
+ user :: binary() | undefined,
14
+ services :: [atom()]
15
+ }).
16
+ -type state() :: #state{} .
17
+
18
+
19
+
20
+ -spec start_link([{atom(), atom()}]) -> {ok, pid()} .
21
+
22
+ start_link(Services) ->
23
+ bertrpc:listen_link({local, ?MODULE}, ?MODULE, Services, 3457).
24
+
25
+
26
+
27
+ -spec init([{atom(), atom()}]) -> {ok, state()} .
28
+
29
+ init(Services) ->
30
+ {ok, #state{ services = Services }}.
31
+
32
+
33
+
34
+ handle_call({machines, F, A, I}, From, State) ->
35
+ cap_external_machines_api:handle_call({F, A, I}, From, State);
36
+
37
+ handle_call({gems, F, A, I}, From, State) ->
38
+ cap_external_gems_api:handle_call({F, A, I}, From, State);
39
+
40
+ handle_call({applications, F, A, I}, From, State) ->
41
+ cap_external_apps_api:handle_call({F, A, I}, From, State);
42
+
43
+ handle_call({M, F, A, I}, From, State) ->
44
+ #state { services = Services } = State,
45
+ case proplists:get_value(M, Services) of
46
+ undefined ->
47
+ {reply, {error, service_not_found}, State};
48
+ Module ->
49
+ Module:handle_call({F, A, I}, From, State)
50
+ end.
51
+
52
+
53
+
54
+ handle_cast({machines, F, A, I}, State) ->
55
+ cap_external_machines_api:handle_cast({F, A, I}, State);
56
+
57
+ handle_cast({gems, F, A, I}, State) ->
58
+ cap_external_gems_api:handle_cast({F, A, I}, State);
59
+
60
+ handle_cast({applications, F, A, I}, State) ->
61
+ cap_external_apps_api:handle_cast({F, A, I}, State);
62
+
63
+ handle_cast({M, F, A, I}, State) ->
64
+ #state { services = Services } = State,
65
+ case proplists:get_value(M, Services) of
66
+ undefined ->
67
+ {noreply, State};
68
+ Module ->
69
+ Module:handle_cast({F, A, I}, State)
70
+ end.
71
+
72
+
73
+
74
+ handle_info(_Info, State) ->
75
+ {noreply, State}.
76
+
77
+
78
+
79
+ terminate(_Reason, _State) ->
80
+ ok.
81
+
82
+
83
+
84
+ code_change(_OldVsn, State, _Extra) ->
85
+ {ok, State}.
86
+
87
+
@@ -0,0 +1,125 @@
1
+ -module(cap_external_apps_api).
2
+ -export([handle_call/3, handle_cast/2]).
3
+
4
+
5
+
6
+ handle_call({all,
7
+ [Node], _},
8
+ _From, State) ->
9
+ try
10
+ All = cap_machine_apps:all(Node),
11
+ {reply, {ok, All}, State}
12
+ catch
13
+ throw:T -> {reply, {error, T}, State}
14
+ end;
15
+
16
+
17
+
18
+ handle_call({create,
19
+ [Node, Name, Domains, Env], _},
20
+ _From, State) ->
21
+ try
22
+ ok = cap_machine_apps:create(Node, Name, Domains, Env, [<<"my_gem">>]),
23
+ {reply, true, State}
24
+ catch
25
+ throw:T -> {reply, {error, T}, State}
26
+ end;
27
+
28
+
29
+
30
+ handle_call({import,
31
+ [Node, Name, Domains, Env, Root, Gems, Uid, Gid], _},
32
+ _From, State) ->
33
+ try
34
+ ok = cap_machine_apps:import(Node,
35
+ Name,
36
+ Domains,
37
+ Env,
38
+ Gems,
39
+ Root,
40
+ Uid,
41
+ Gid),
42
+ {reply, true, State}
43
+ catch
44
+ throw:T -> {reply, {error, T}, State}
45
+ end;
46
+
47
+
48
+
49
+ handle_call({restart,
50
+ [Node, Id], _},
51
+ _From, State) ->
52
+ try
53
+ ok = cap_application:restart({Node, Id}),
54
+ {reply, true, State}
55
+ catch
56
+ throw:T -> {reply, {error, T}, State}
57
+ end;
58
+
59
+
60
+
61
+ handle_call({start,
62
+ [Node, Id], _},
63
+ _From, State) ->
64
+ try
65
+ ok = cap_application:start({Node, Id}),
66
+ {reply, true, State}
67
+ catch
68
+ throw:T -> {reply, {error, T}, State}
69
+ end;
70
+
71
+
72
+
73
+ handle_call({stop,
74
+ [Node, Id], _},
75
+ _From, State) ->
76
+ try
77
+ ok = cap_application:stop({Node, Id}),
78
+ {reply, true, State}
79
+ catch
80
+ throw:T -> {reply, {error, T}, State}
81
+ end;
82
+
83
+
84
+
85
+ handle_call({relink,
86
+ [Node, Id], _},
87
+ _From, State) ->
88
+ try
89
+ ok = cap_application:relink({Node, Id}),
90
+ {reply, true, State}
91
+ catch
92
+ throw:T -> {reply, {error, T}, State}
93
+ end;
94
+
95
+
96
+
97
+ handle_call({update,
98
+ [Node, Id, NewDomains, NewGems], _},
99
+ _From, State) ->
100
+ try
101
+ ok = cap_machine_apps:update(Node, Id, NewDomains, NewGems),
102
+ {reply, true, State}
103
+ catch
104
+ throw:T -> {reply, {error, T}, State}
105
+ end;
106
+
107
+
108
+
109
+ handle_call({fupdate,
110
+ [Node, Id], _},
111
+ _From, State) ->
112
+ try
113
+ ok = cap_machine_apps:fupdate(Node, Id),
114
+ {reply, true, State}
115
+ catch
116
+ throw:T -> {reply, {error, T}, State}
117
+ end.
118
+
119
+
120
+
121
+ handle_cast({_, _, _},
122
+ State) ->
123
+ {noreply, State}.
124
+
125
+
@@ -0,0 +1,85 @@
1
+ -module(cap_external_gems_api).
2
+ -export([handle_call/3, handle_cast/2]).
3
+
4
+
5
+
6
+ handle_call({push,
7
+ _, Info},
8
+ _From, State) ->
9
+ case proplists:get_value(stream, Info) of
10
+ undefined ->
11
+ Reason = {user, 1, <<"CapricornGemError">>,
12
+ <<"This is not a gem">>, []},
13
+ {reply, {error, Reason}, State};
14
+
15
+ _WeHaveAStream ->
16
+ try
17
+ {ok, Data} = collect_stream_data(sof, []),
18
+ cap_cluster_gems:push(Data)
19
+ of
20
+ {ok,Missing} ->
21
+ {reply, {ok,Missing}, State};
22
+
23
+ {error,already_present} ->
24
+ Reason = {user, 1, <<"CapricornGemError">>,
25
+ <<"This gem is already present in the cluster.">>, []},
26
+ {reply, {error, Reason}, State};
27
+
28
+ {error,{[gem_error,ErrorMessage]}} ->
29
+ Reason = {user, 1, <<"CapricornGemError">>, ErrorMessage, []},
30
+ {reply, {error, Reason}, State};
31
+
32
+ {error,{[not_found]}} ->
33
+ Reason = {user, 1, <<"CapricornGemError">>,
34
+ <<"Transfering failed!">>, []},
35
+ {reply, {error, Reason}, State}
36
+
37
+ catch
38
+ throw:T -> {reply, {error, T}, State}
39
+ end
40
+ end;
41
+
42
+
43
+
44
+ handle_call({all,
45
+ _, _},
46
+ _From, State) ->
47
+ try
48
+ {ok, All} = cap_cluster_gems:all(),
49
+ {reply, {ok, All}, State}
50
+ catch
51
+ throw:T -> {reply, {error, T}, State}
52
+ end;
53
+
54
+
55
+
56
+ handle_call({missing,
57
+ _, _},
58
+ _From, State) ->
59
+ try
60
+ {ok, Missing} = cap_cluster_gems:missing(),
61
+ {reply, {ok, Missing}, State}
62
+ catch
63
+ throw:T -> {reply, {error, T}, State}
64
+ end.
65
+
66
+
67
+
68
+ handle_cast(_, State) ->
69
+ {noreply, State}.
70
+
71
+
72
+
73
+ collect_stream_data(sof, Acc) ->
74
+ collect_stream_data(bertrpc:stream(), Acc);
75
+
76
+ collect_stream_data({ok, eof}, Acc) ->
77
+ {ok, list_to_binary(lists:reverse(Acc))};
78
+
79
+ collect_stream_data({error, Reason}, _) ->
80
+ {error, Reason};
81
+
82
+ collect_stream_data({ok, Data}, Acc) ->
83
+ collect_stream_data(bertrpc:stream(), [Data|Acc]).
84
+
85
+
@@ -0,0 +1,18 @@
1
+ -module(cap_external_machines_api).
2
+ -export([handle_call/3, handle_cast/2]).
3
+
4
+
5
+
6
+ handle_call({all,
7
+ _, _},
8
+ _From, State) ->
9
+ Nodes = [atom_to_list(Node) || Node <- nodes()],
10
+ Machines = [list_to_atom(Node) || Node <- Nodes, string:substr(Node, 1, 8) == "machine-"],
11
+ {reply, Machines, State}.
12
+
13
+
14
+
15
+ handle_cast(_, State) ->
16
+ {noreply, State}.
17
+
18
+
@@ -0,0 +1,111 @@
1
+ -module(cap_gem_utils).
2
+ -include("capricorn.hrl").
3
+
4
+
5
+ -export([match_requirements/2, find_matches/2, match_requirement/2]).
6
+
7
+
8
+ %%% External API
9
+ find_matches(Versions, Requirements) ->
10
+ find_matches(Versions, Requirements, []).
11
+
12
+ find_matches([], _Requirements, Acc) ->
13
+ Acc;
14
+
15
+ find_matches([Version|Other], Requirements, Acc) ->
16
+ case match_requirements(Version, Requirements) of
17
+ true -> find_matches(Other, Requirements, [Version|Acc]);
18
+ false -> find_matches(Other, Requirements, Acc)
19
+ end.
20
+
21
+
22
+ match_requirements(_, []) ->
23
+ true;
24
+
25
+ match_requirements(Version, [Req|Rest]) ->
26
+ case match_requirement(Version, Req) of
27
+ true -> match_requirements(Version, Rest);
28
+ false -> false
29
+ end.
30
+
31
+
32
+ %%% Internal API
33
+ -spec balance_versions(version(), version()) -> {version(), version()}.
34
+ balance_versions({A},{B}) ->
35
+ if
36
+ length(A) > length(B) ->
37
+ case lists:nth(length(B)+1, A) of
38
+ E when is_list(E) ->
39
+ balance_versions({A}, {B++[[255]]});
40
+ _ ->
41
+ balance_versions({A}, {B++[0]})
42
+ end;
43
+ length(A) < length(B) ->
44
+ case lists:nth(length(A)+1, B) of
45
+ E when is_list(E) ->
46
+ balance_versions({A++[[255]]}, {B});
47
+ _ ->
48
+ balance_versions({A++[0]}, {B})
49
+ end;
50
+ length(A) == length(B) ->
51
+ {{A},{B}};
52
+ true ->
53
+ {{A},{B}}
54
+ end.
55
+
56
+
57
+ -spec release_version(version()) -> version().
58
+ release_version({Parts}) ->
59
+ {release_version(Parts, [])}.
60
+
61
+ -spec release_version(version_parts(), list()) -> version_parts().
62
+ release_version([], Acc) ->
63
+ lists:reverse(Acc);
64
+ release_version([Part|_], Acc) when is_list(Part) ->
65
+ lists:reverse(Acc);
66
+ release_version([Part|Rest], Acc) when is_integer(Part) ->
67
+ release_version(Rest, [Part|Acc]).
68
+
69
+
70
+ -spec bump_version(version()) -> version().
71
+ bump_version(Version) ->
72
+ {Parts1} = release_version(Version),
73
+ Parts2 = if
74
+ length(Parts1) > 1 ->
75
+ lists:sublist(Parts1, length(Parts1)-1);
76
+ true -> Parts1
77
+ end,
78
+ [Last|Rest] = lists:reverse(Parts2),
79
+ Parts3 = lists:reverse([Last+1|Rest]),
80
+ {Parts3}.
81
+
82
+ -spec match_requirement(version(), requirement()) -> boolean().
83
+ match_requirement(Version, {'=', RVersion}) ->
84
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
85
+ Version1 == RVersion1;
86
+
87
+ match_requirement(Version, {'!=', RVersion}) ->
88
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
89
+ Version1 /= RVersion1;
90
+
91
+ match_requirement(Version, {'<', RVersion}) ->
92
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
93
+ Version1 < RVersion1;
94
+
95
+ match_requirement(Version, {'>', RVersion}) ->
96
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
97
+ Version1 > RVersion1;
98
+
99
+ match_requirement(Version, {'>=', RVersion}) ->
100
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
101
+ Version1 >= RVersion1;
102
+
103
+ match_requirement(Version, {'<=', RVersion}) ->
104
+ {Version1, RVersion1} = balance_versions(Version, RVersion),
105
+ Version1 =< RVersion1;
106
+
107
+ match_requirement(Version, {'~>', RVersion}) ->
108
+ Version1 = release_version(Version),
109
+ RVersion1 = bump_version(RVersion),
110
+ match_requirement(Version1, {'>=', RVersion}) and
111
+ match_requirement(Version1, {'<', RVersion1}).