Skip to content

Commit

Permalink
command line flags, help
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro Lytovchenko committed Feb 9, 2014
1 parent 2976ccf commit a957756
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 296 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
compile: compile:
rebar get-deps compile escriptize rebar get-deps compile escriptize


.PHONY: clean
clean:
rm ebin/* *.log

#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
OTP_PLT = .epm_otp.plt OTP_PLT = .epm_otp.plt
COMBO_PLT = .epm_combo.plt COMBO_PLT = .epm_combo.plt
Expand Down
27 changes: 16 additions & 11 deletions include/epm.hrl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,36 +2,41 @@
-define(epm_year, 2014). -define(epm_year, 2014).
-define(DEFAULT_API_MODULES, [github_api]). -define(DEFAULT_API_MODULES, [github_api]).


-define(any_author, any_author). -define(any_name, any_n).
-define(any_platform, any_platform). -define(any_author, any_a).
-define(any_vsn, any_vsn). -define(any_platform, any_p).
-define(any_erlang_vsn, any_erlang_vsn). -define(any_vsn, any_v).
-define(any_erlang_vsn, any_e).


-define(EPM_FAIL(Format, Args), begin exit({error, epm:s(Format, Args)}) end). -define(EPM_FAIL(Format, Args), begin exit({error, epm:s(Format, Args)}) end).
-define(EPM_EXIT(Format, Args), begin exit({ok, epm:s(Format, Args)}) end). -define(EPM_EXIT(Format, Args), begin exit({ok, epm:s(Format, Args)}) end).


-type platform() :: x86 | x64 | ?any_platform. -type platform() :: x86 | x64 | ?any_platform.
-type erlangvsn() :: binary(). -type erlangvsn() :: binary().
-type api_module() :: epm_api_github.
-type pkg_arg() :: source | {tag|branch|hash, string()}.


-record(repoid, { name :: string() -record(repoid, { name :: string()
}). }).
-type repoid() :: #repoid{}. -type repoid() :: #repoid{}.


%% Unified global identifier for package %% Unified global identifier for package
-record(pkgid, { author=?any_author :: string() | ?any_author -record(pkgid, { author = ?any_author :: string() | ?any_author
, pkg_name :: string() , pkg_name = ?any_name :: string() | ?any_name
, platform=?any_platform :: platform() , platform = ?any_platform :: platform()
, vsn=?any_vsn :: string() | ?any_vsn , vsn = ?any_vsn :: string() | ?any_vsn
, erlang_vsn=?any_erlang_vsn :: erlangvsn() | ?any_erlang_vsn , erlang_vsn = ?any_erlang_vsn :: erlangvsn() | ?any_erlang_vsn
}). %% arguments passed from command line, like: source, {tag|branch|hash, x}
, args=[] :: [pkg_arg()]
}).
-type pkgid() :: #pkgid{}. -type pkgid() :: #pkgid{}.


-record(repo, { id :: repoid() -record(repo, { id :: repoid()
, description :: string() , description :: string()
, url :: string() , url :: string()
%, followers %, followers
%, pushed %, pushed
, api_module , api_module=epm_api_github :: api_module()
}). }).
-type repo() :: #repo{}. -type repo() :: #repo{}.


Expand Down
17 changes: 15 additions & 2 deletions src/epm.erl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
, matches/2 , matches/2
, platform/1 , platform/1
, p/3, p/2, p/1 , p/3, p/2, p/1
, s/2, pkgid_match_spec/1]). , s/2, pkgid_match_spec/1, args/1, arg_bool/2, arg/2, set_arg_bool/3]).


-include("epm.hrl"). -include("epm.hrl").
-include_lib("stdlib/include/ms_transform.hrl"). -include_lib("stdlib/include/ms_transform.hrl").
Expand Down Expand Up @@ -58,15 +58,28 @@ platform(#pkgid{platform=X}) -> X.
erlang_vsn(#pkg{id=#pkgid{erlang_vsn=X}}) -> X; erlang_vsn(#pkg{id=#pkgid{erlang_vsn=X}}) -> X;
erlang_vsn(#pkgid{erlang_vsn=X}) -> X. erlang_vsn(#pkgid{erlang_vsn=X}) -> X.


args(#pkgid{args=X}) -> X.

arg_bool(Arg, #pkgid{args=X}) -> lists:member(Arg, X).

arg(Arg, #pkgid{args=X}) -> proplists:get_value(Arg, X).

set_arg_bool(Arg, false, #pkgid{args=Args}=Pkgid) ->
Pkgid#pkgid{args = lists:delete(Arg, Args)};
set_arg_bool(Arg, true, #pkgid{args=Args}=Pkgid) ->
Pkgid#pkgid{args = [Arg | lists:delete(Arg, Args)]}.

%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
as_string(#pkg{id=Id}) -> as_string(Id); as_string(#pkg{id=Id}) -> as_string(Id);
as_string(#pkgid{author=A, pkg_name=N, vsn=V, platform=P, erlang_vsn=E}) -> as_string(#pkgid{ author=A, pkg_name=N, vsn=V, platform=P, erlang_vsn=E
, args=Args}) ->
"[" "["
++ case A of ?any_author -> ""; _ -> s("~s/", [A]) end ++ case A of ?any_author -> ""; _ -> s("~s/", [A]) end
++ N ++ N
++ case V of ?any_vsn -> ""; _ -> s(", ~s", [V]) end ++ case V of ?any_vsn -> ""; _ -> s(", ~s", [V]) end
++ case P of ?any_platform -> ""; _ -> s(", ~s", [P]) end ++ case P of ?any_platform -> ""; _ -> s(", ~s", [P]) end
++ case E of ?any_erlang_vsn -> ""; _ -> s(", ~s", [E]) end ++ case E of ?any_erlang_vsn -> ""; _ -> s(", ~s", [E]) end
++ case Args of [] -> ""; _ -> s(" ~p", [Args]) end
++ "]"; ++ "]";
as_string(#repo{id=I, description=_D, url=U}) -> as_string(#repo{id=I, description=_D, url=U}) ->
s("[Repo ~s url=~s]", [I, U]); s("[Repo ~s url=~s]", [I, U]);
Expand Down
23 changes: 23 additions & 0 deletions src/epm_api_github.erl
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,23 @@
%%%-------------------------------------------------------------------
%%% @author Dmytro Lytovchenko <dmytro.lytovchenko@gmail.com>
%%% @doc Handles Github repositories
%%% @end
%%% Created : 09. Feb 2014 8:16 PM
%%%-------------------------------------------------------------------
-module(epm_api_github).
-behaviour(gen_epm_api).

%% API
-export([get_source/2]).

-include("epm.hrl").

-spec get_source(Pkg :: pkg(), DestDir :: string()) -> ok | {error, any()}.
get_source(Pkg=#pkg{id=#pkgid{author=A, pkg_name=N}}, DestDir) ->
Url = get_vcs_url(Pkg),
epm_util:git(["clone", Url, DestDir ++ epm:s("/~s_~s", [A, N])]).

get_vcs_url(#pkg{id=#pkgid{author=?any_author}}) -> {error, author};
get_vcs_url(#pkg{id=#pkgid{pkg_name=?any_name}}) -> {error, pkg_name};
get_vcs_url(#pkg{id=#pkgid{author=A, pkg_name=N}}) ->
epm:s("https://github.com/~s/~s.git", [A, N]).
152 changes: 75 additions & 77 deletions src/epm_core.erl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -151,51 +151,50 @@ execute(_State=#epm_state{}, ["config" | Args]) ->
end; end;


execute(_State=#epm_state{}, _) -> execute(_State=#epm_state{}, _) ->
io:format("Usage: epm commands~n~n"), epm:p("Usage: epm commands~n~n"
io:format(" install [<user>/]<project> {project options}, ... {global options}~n"), " install [<author>/]<project> {project options}, ... {global options}~n"
io:format(" project options:~n"), " project options:~n"
io:format(" --tag <tag>~n"), " --source :: requests source install (does not build)~n"
io:format(" --branch <branch>~n"), " --platform x86|x64, --vsn <v>, --tag <t>, --branch <b>, --hash <h>~n"
io:format(" --sha <sha>~n"), %% " --with-deps (default)~n"
io:format(" --with-deps (default)~n"), %% " --without-deps~n"
io:format(" --without-deps~n"), %% " --prebuild-command <cmd>~n"
io:format(" --prebuild-command <cmd>~n"), %% " --build-command <cmd>~n"
io:format(" --build-command <cmd>~n"), %% " --test-command <cmd>~n"
io:format(" --test-command <cmd>~n"), " global options:~n"
io:format(" global options:~n"), %% " --verbose~n"
io:format(" --verbose~n"), " --config-set <key> <value>~n~n"
io:format(" --config-set <key> <value>~n~n"), %% " remove [<user>/]<project> {project options}, ... {global options}~n"
io:format(" remove [<user>/]<project> {project options}, ... {global options}~n"), %% " project options:~n"
io:format(" project options:~n"), %% " --tag <tag>~n"
io:format(" --tag <tag>~n"), %% " --branch <branch>~n"
io:format(" --branch <branch>~n"), %% " --sha <sha>~n"
io:format(" --sha <sha>~n"), %% " global options:~n"
io:format(" global options:~n"), %% " --verbose~n~n"
io:format(" --verbose~n~n"), %% " --config-set <key> <value>~n~n"
io:format(" --config-set <key> <value>~n~n"), %% " update [<user>/]<project> {project options}, ... {global options}~n"
io:format(" update [<user>/]<project> {project options}, ... {global options}~n"), %% " project options:~n"
io:format(" project options:~n"), %% " --tag <tag>~n"
io:format(" --tag <tag>~n"), %% " --branch <branch>~n"
io:format(" --branch <branch>~n"), %% " --sha <sha>~n"
io:format(" --sha <sha>~n"), %% " --with-deps~n"
io:format(" --with-deps~n"), %% " --without-deps (default)~n"
io:format(" --without-deps (default)~n"), %% " global options:~n"
io:format(" global options:~n"), %% " --verbose~n~n"
io:format(" --verbose~n~n"), %% " --config-set <key> <value>~n~n"
io:format(" --config-set <key> <value>~n~n"), %% " info [<user>/]<project>, ... {global options}~n"
io:format(" info [<user>/]<project>, ... {global options}~n"), %% " global options:~n"
io:format(" global options:~n"), %% " --config-set <key> <value>~n~n"
io:format(" --config-set <key> <value>~n~n"), %% " search <project>, ... {global options}~n"
io:format(" search <project>, ... {global options}~n"), %% " global options:~n"
io:format(" global options:~n"), %% " --config-set <key> <value>~n~n"
io:format(" --config-set <key> <value>~n~n"), %% " list~n~n"
io:format(" list~n~n"), %% " latest~n~n"
io:format(" latest~n~n"), " config {options}~n"
io:format(" config {options}~n"), " options:~n"
io:format(" options:~n"), " --get (default)~n"
io:format(" --get (default)~n"), " --set <key> <value>~n"
io:format(" --set <key> <value>~n"), " --remove <key>~n"),
io:format(" --remove <key>~n"),
ok. ok.


%% ----------------------------------------------------------------------------- %% -----------------------------------------------------------------------------
Expand All @@ -209,32 +208,32 @@ collect_args(Target, Args) ->


-spec collect_args_internal(Target :: atom() -spec collect_args_internal(Target :: atom()
, Args :: [string()] , Args :: [string()]
, Packages :: [#pkgid{}] , Pkgids :: [#pkgid{}]
, Flags :: [atom()]) , Flags :: [atom()])
-> {[#pkgid{}], [atom()]}. -> {[#pkgid{}], [atom()]}.
collect_args_internal(_, [], Packages, Flags) -> collect_args_internal(_, [], Packages, Flags) ->
{lists:reverse(Packages), lists:reverse(Flags)}; {lists:reverse(Packages), lists:reverse(Flags)};
collect_args_internal(Target, [Arg | Rest], Packages, Flags) -> collect_args_internal(Target, [Arg | Rest], Pkgids, Flags) ->
case parse_tag(Target, Arg) of case parse_tag(Target, Arg) of
undefined -> %% if not a tag then must be a project name undefined -> %% if not a tag then must be a project name
%% split into user and project %% split into user and project
{ProjectName, User} = epm_ops:split_package(Arg), {ProjectName, User} = epm_ops:split_package(Arg),
collect_args_internal(Target, Rest collect_args_internal(Target, Rest
, [#pkgid{author=User, pkg_name=ProjectName}|Packages] , [#pkgid{author=User, pkg_name=ProjectName}|Pkgids]
, Flags); , Flags);
{Type, Tag, 0} -> %% tag with no trailing value {Type, Tag, 0} -> %% tag with no trailing value
case Type of case Type of
%% project -> project ->
%% [#pkg{args = Args} = Package|OtherPackages] = Packages, %% Update head of Pkgids with additional arg
%% collect_args_internal(Target, Rest [#pkgid{args=Args} = Pkgid|Tail] = Pkgids,
%% , [Package#pkg{args = Args ++ [Tag]}|OtherPackages] Pkgid1 = Pkgid#pkgid{ args = Args ++ [Tag] },
%% , Flags); collect_args_internal(Target, Rest, [Pkgid1 | Tail], Flags);
global -> global ->
collect_args_internal(Target, Rest, Packages, [Tag|Flags]) collect_args_internal(Target, Rest, Pkgids, [Tag|Flags])
end; end;
{Type, Tag, NumVals} when is_integer(NumVals) -> % tag with trailing value(s) {Type, Tag, NumVals} when is_integer(NumVals) -> % tag with trailing value(s)
if length(Rest) < NumVals -> if length(Rest) < NumVals ->
exit("poorly formatted command"); ?EPM_FAIL("poorly formatted command", []);
true -> ok true -> ok
end, end,
{Vals, Rest1} = lists:split(NumVals, Rest), {Vals, Rest1} = lists:split(NumVals, Rest),
Expand All @@ -243,17 +242,15 @@ collect_args_internal(Target, [Arg | Rest], Packages, Flags) ->
_ -> Vals _ -> Vals
end, end,
case Type of case Type of
%% project -> project ->
%% %% this tag applies to the last project on the stack %% Update head of Pkgids with additional arg
%% [#pkg{args=Args}=Package | OtherPackages] = Packages, %% this tag applies to the last project on the stack
%% Vsn = if Tag == tag; Tag == branch; Tag == sha -> Vals1; [#pkgid{args=Args}=Pkgid | Tail] = Pkgids,
%% true -> Package#pkg.vsn Vsn = if Tag == tag; Tag == branch; Tag == hash -> Vals1;
%% end, true -> Pkgid#pkgid.vsn
%% collect_args_internal( Target, Rest1 end,
%% , [Package#pkg{ vsn = Vsn Pkgid2 = Pkgid#pkgid{ vsn = Vsn, args = Args ++ [{Tag, Vals1}] },
%% , args = Args ++ [{Tag, Vals1}] collect_args_internal( Target, Rest1, [Pkgid2 | Tail], Flags);
%% } | OtherPackages]
%% , Flags);
global -> global ->
if Tag == config_set -> if Tag == config_set ->
[K, V1] = Vals1, [K, V1] = Vals1,
Expand All @@ -264,7 +261,7 @@ collect_args_internal(Target, [Arg | Rest], Packages, Flags) ->
end; end;
true -> ok true -> ok
end, end,
collect_args_internal(Target, Rest1, Packages, [{Tag, Vals1}|Flags]) collect_args_internal(Target, Rest1, Pkgids, [{Tag, Vals1}|Flags])
end end
end. end.


Expand All @@ -273,19 +270,20 @@ collect_args_internal(Target, [Arg | Rest], Packages, Flags) ->
%% Arg = string() %% Arg = string()
%% Tag = atom() %% Tag = atom()
%% HasValue = bool() %% HasValue = bool()
parse_tag(install, "--source") -> {project, source, 0};
parse_tag(install, "--tag") -> {project, tag, 1}; parse_tag(install, "--tag") -> {project, tag, 1};
parse_tag(install, "--branch") -> {project, branch, 1}; parse_tag(install, "--branch") -> {project, branch, 1};
parse_tag(install, "--sha") -> {project, sha, 1}; parse_tag(install, "--hash") -> {project, hash, 1};
parse_tag(install, "--prebuild-command") -> {project, prebuild_command, 1}; %% parse_tag(install, "--prebuild-command") -> {project, prebuild_command, 1};
parse_tag(install, "--build-command") -> {project, build_command, 1}; %% parse_tag(install, "--build-command") -> {project, build_command, 1};
parse_tag(install, "--test-command") -> {project, test_command, 1}; %% parse_tag(install, "--test-command") -> {project, test_command, 1};


parse_tag(info, "--tag") -> {project, tag, 1}; %% parse_tag(info, "--tag") -> {project, tag, 1};
parse_tag(info, "--branch") -> {project, branch, 1}; %% parse_tag(info, "--branch") -> {project, branch, 1};
parse_tag(info, "--sha") -> {project, sha, 1}; %% parse_tag(info, "--sha") -> {project, sha, 1};


parse_tag(_, "--with-deps") -> {project, with_deps, 0}; %% parse_tag(_, "--with-deps") -> {project, with_deps, 0};
parse_tag(_, "--without-deps") -> {project, without_deps, 0}; %% parse_tag(_, "--without-deps") -> {project, without_deps, 0};


parse_tag(config, "--get") -> {global, get, 0}; parse_tag(config, "--get") -> {global, get, 0};
parse_tag(config, "--set") -> {global, set, 2}; parse_tag(config, "--set") -> {global, set, 2};
Expand Down Expand Up @@ -314,7 +312,7 @@ update_epm(_State) ->
{ok, {{_, 200, _}, _, Body}} -> {ok, {{_, 200, _}, _, Body}} ->
case file:write_file(File, Body) of case file:write_file(File, Body) of
ok -> ok ->
io:format("+ updated epm (~s) to latest version~n", [File]); epm:p("+ updated epm (~s) to latest version~n", [File]);
{error, Reason} -> {error, Reason} ->
exit(lists:flatten(io_lib:format("failed to overwrite epm executable ~s: ~p~n", [File, Reason]))) exit(lists:flatten(io_lib:format("failed to overwrite epm executable ~s: ~p~n", [File, Reason])))
end; end;
Expand Down
11 changes: 9 additions & 2 deletions src/epm_deps.erl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ resolve_dependencies(Pkgids) ->
resolve_dependencies_internal(Pkgids, Pkgids) -> Pkgids; resolve_dependencies_internal(Pkgids, Pkgids) -> Pkgids;
resolve_dependencies_internal(Pkgids, _Previous) -> resolve_dependencies_internal(Pkgids, _Previous) ->
F = fun(Pkgid=#pkgid{}, A) -> F = fun(Pkgid=#pkgid{}, A) ->
SourceFlag = epm:arg_bool(source, Pkgid),
PkgList = epm_index:list_global_matching(Pkgid), PkgList = epm_index:list_global_matching(Pkgid),
lists:foldl(fun(Dep, A1) -> ordsets:add_element(Dep, A1) end lists:foldl(fun(Dep, A1) ->
, A, lists:flatten([Pkg#pkg.deps || Pkg <- PkgList])) % source flag spreads over all deps
Dep1 = epm:set_arg_bool(source, SourceFlag, Dep),
ordsets:add_element(Dep1, A1)
end, A, lists:flatten([Pkg#pkg.deps || Pkg <- PkgList]))
end, end,
%% For all the package ids get matching packages (TODO: Get 1 best candidate)
%% and merge it with all the dependency ids

PkgidsPlusDeps = lists:foldl(F, ordsets:from_list(Pkgids), Pkgids), PkgidsPlusDeps = lists:foldl(F, ordsets:from_list(Pkgids), Pkgids),
resolve_dependencies_internal(PkgidsPlusDeps, Pkgids). resolve_dependencies_internal(PkgidsPlusDeps, Pkgids).
Loading

0 comments on commit a957756

Please sign in to comment.