Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

color prints, index search, install (wip)

  • Loading branch information...
commit 2456f5185af4259b66cd886cdc461bf5627d4231 1 parent 8370e02
Dmytro Lytovchenko authored
View
17 include/epm.hrl
@@ -3,10 +3,13 @@
-define(DEFAULT_API_MODULES, [github_api]).
-define(any_author, any_author).
--define(any_vsn, any_vsn).
-define(any_platform, any_platform).
+-define(any_vsn, any_vsn).
+-define(any_erlang_vsn, any_erlang_vsn).
+
+-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(EXIT(Format, Args), exit(lists:flatten(io_lib:format(Format, Args)))).
-type platform() :: x86 | x64 | ?any_platform.
-type erlangvsn() :: binary().
@@ -19,7 +22,7 @@
, pkg_name :: string()
, platform=?any_platform :: platform()
, vsn=?any_vsn :: string() | ?any_vsn
- , erlang_vsn=?any_vsn :: erlangvsn() | ?any_vsn
+ , erlang_vsn=?any_erlang_vsn :: erlangvsn() | ?any_erlang_vsn
}).
-type pkgid() :: #pkgid{}.
@@ -49,8 +52,8 @@
%% State of the application, contains loaded local index, installed apps and
%% remote index
--record(epm_state, { local_available=[] :: [pkg()]
- , installed=[] :: [installed_pkg()]
- , remote_available=[] :: [pkg()]
- , repositories=[] :: [repo()]
+-record(epm_state, { installed=[] :: [installed_pkg()]
+ , global_index=[] :: [pkg()]
+ %, local_index=[] :: [pkg()]
+ %, repos=[] :: [repo()]
}).
View
59 src/epm.erl
@@ -5,8 +5,10 @@
, vsn/1
, erlang_vsn/1
, as_string/1
- , equals/2
- , platform/1]).
+ , matches/2
+ , platform/1
+ , p/3, p/2, p/1
+ , s/2]).
-include("epm.hrl").
@@ -17,8 +19,9 @@ main(Args) ->
, [sasl, crypto, public_key, ssl, ibrowse, epm]),
case (catch main_internal(Args)) of
- {'EXIT', Msg} when is_list(Msg) -> io:format("- ~s~n", [Msg]);
- {'EXIT', Other} -> io:format("~p~n", [Other]);
+ {'EXIT', {ok, Msg}} when is_list(Msg) -> epm:p(red, "- ~s~n", [Msg]);
+ {'EXIT', {error, Msg}} when is_list(Msg) -> epm:p(green, "- ~s~n", [Msg]);
+ {'EXIT', Other} -> epm:p(dark_cyan, "~p~n", [Other]);
_ -> ok
end,
epm_index:close(),
@@ -66,9 +69,45 @@ as_string(#repoid{name=N}) ->
lists:flatten(io_lib:format("Repo id ~s", [N]));
as_string(undefined) -> "undefined".
-equals(#pkgid{}=P1, #pkgid{}=P2) ->
- (author(P1) =:= author(P2) orelse author(P2) =:= ?any_author)
- andalso (name(P1) =:= name(P2))
- andalso (vsn(P1) =:= vsn(P2) orelse vsn(P1) =:= ?any_vsn)
- andalso (erlang_vsn(P1) =:= erlang_vsn(P2) orelse erlang_vsn(P1) =:= ?any_vsn)
- andalso (platform(P1) =:= platform(P2)).
+%% @doc Checks that P1 with some wildcard fields matches P2
+matches(#pkgid{}=P1, #pkgid{}=P2) ->
+ P1Author = author(P1),
+ P1V = vsn(P1),
+ P1Erlang = erlang_vsn(P1),
+ P1Platf = platform(P1),
+ ( name(P1) =:= name(P2)
+ andalso (P1Author =:= author(P2) orelse P1Author =:= ?any_author)
+ andalso (P1V =:= vsn(P2) orelse P1V =:= ?any_vsn)
+ andalso (P1Erlang =:= erlang_vsn(P2) orelse P1Erlang =:= ?any_erlang_vsn)
+ andalso (P1Platf =:= platform(P2) orelse P1Platf =:= ?any_platform)
+ ).
+
+%% @doc Uncolored print
+p(Text) -> io:format(Text).
+
+%% @doc Colored print and formatted uncolored print
+p(Color, Text) when is_atom(Color) ->
+ io:format(ansi_color(Color) ++ Text ++ ansi_endfont());
+p(Text, Args) -> io:format(Text, Args).
+
+%% @doc Formatted colored print
+p(Color, Format, Args) when is_atom(Color) ->
+ io:format(ansi_color(Color) ++ Format ++ ansi_endfont() ++ "~n", Args).
+
+%% @doc sprintf
+s(Format, Args) ->
+ lists:flatten(io_lib:format(Format, Args)).
+
+%% @doc ANSI ESCape color codes: reset font color/weight
+ansi_endfont() -> [27 | "[0m"].
+
+%% @doc ANSI ESCape color codes: font color
+ansi_color(black) -> [27 | "[1;30m"];
+ansi_color(red) -> [27 | "[1;31m"];
+ansi_color(green) -> [27 | "[1;32m"];
+ansi_color(yellow) -> [27 | "[1;33m"];
+ansi_color(blue) -> [27 | "[1;34m"];
+ansi_color(magenta) -> [27 | "[1;35m"];
+ansi_color(cyan) -> [27 | "[1;36m"];
+ansi_color(white) -> [27 | "[1;37m"];
+ansi_color(dark_cyan) -> [27 | "[2;36m"].
View
4 src/epm_cfg.erl
@@ -46,7 +46,7 @@ init() ->
file:write_file(filename:join([Home, ".epm"]), <<>>),
[];
{error, Reason} ->
- ?EXIT("failed to read epm global config: ~p", [Reason])
+ ?EPM_FAIL("failed to read epm global config: ~p", [Reason])
end,
lists:foreach(fun({K, V}) -> set(K, V) end, GlobalConfig).
@@ -98,5 +98,5 @@ write_config_file() ->
io:format(IoDevice, "~n].~n", []),
io:format("+ updated .epm config~n");
{error, Reason} ->
- ?EXIT("failed to update .epm config (~s): ~p", [FileLoc, Reason])
+ ?EPM_FAIL("failed to update .epm config (~s): ~p", [FileLoc, Reason])
end.
View
29 src/epm_core.erl
@@ -4,30 +4,33 @@
-include("epm.hrl").
execute(State=#epm_state{}, ["install" | Args]) ->
- {Packages, Flags} = collect_args(install, Args),
+ {Pkgids, Flags} = collect_args(install, Args),
epm_cfg:set(verbose, lists:member(verbose, Flags)),
- Deps = epm_deps:package_dependencies(Packages),
+
+ Deps = epm_deps:resolve_dependencies(Pkgids),
+ %Packages = lists:flatten(lists:map(fun epm_index:find_package/1, Pkgids)),
+ epm:p("ids=~p~ndeps=~p~n", [Pkgids, Deps]),
{Installed, NotInstalled} = epm_ops:filter_installed_packages(Deps),
case NotInstalled of
[] ->
- io:format("+ nothing to do: packages and dependencies already installed~n");
+ epm:p("+ nothing to do: packages and dependencies already installed~n");
_ ->
case Installed of
[] -> ok;
_ ->
- io:format("===============================~n"),
- io:format("Packages already installed:~n"),
- io:format("===============================~n"),
- [io:format(" + ~s~n", [epm:as_string(P)]) || P <- Installed]
+ epm:p("===============================~n"
+ "Packages already installed:~n"
+ "===============================~n"),
+ [epm:p(" + ~s~n", [epm:as_string(P)]) || P <- Installed]
end,
- io:format("===============================~n"),
- io:format("Install the following packages?~n"),
- io:format("===============================~n"),
- [io:format(" + ~s~n", [epm:as_string(P)]) || P <- NotInstalled],
- io:format("~n([y]/n) "),
+ epm:p("===============================~n"
+ "Install the following packages?~n"
+ "===============================~n"),
+ [epm:p(" + ~s~n", [epm:as_string(P)]) || P <- NotInstalled],
+ epm:p(yellow, "~n([y]/n) "),
case io:get_chars("", 1) of
C when C == "y"; C == "\n" ->
- io:format("~n"),
+ epm:p("~n"),
lists:foldl(fun(X, St) -> epm_ops:install_package(St, X) end
, State, NotInstalled);
_ -> ok
View
83 src/epm_deps.erl
@@ -7,77 +7,26 @@
-module(epm_deps).
%% API
--export([package_dependencies/1]).
+-export([resolve_dependencies/1]).
-include("epm.hrl").
%% -----------------------------------------------------------------------------
%% Compile list of dependencies
%% -----------------------------------------------------------------------------
-package_dependencies(Packages) ->
- _RepoPlugins = epm_cfg:get(repo_plugins, ?DEFAULT_API_MODULES),
- G = digraph:new(),
- UpdatedPackages = dict:new(),
-%% UpdatedPackages = package_dependencies_internal(
-%% Packages, RepoPlugins, G, undefined, dict:new()),
- Deps = digraph_utils:topsort(G),
- digraph:delete(G),
- [dict:fetch(Dep, UpdatedPackages) || Dep <- Deps].
+-spec resolve_dependencies(Pkgids :: [pkgid()]) -> [pkgid()].
+resolve_dependencies(Pkgids) ->
+ resolve_dependencies_internal(ordsets:from_list(Pkgids), ordsets:new()).
-%% @private
-%% package_dependencies_internal([], _RepoPlugins, _G, _Parent, Dict) -> Dict;
-%% package_dependencies_internal([Package|Tail], RepoPlugins, G
-%% , ParentPkgid=#pkgid{}, Dict) ->
-%% Repo = epm_ops:retrieve_remote_repo(
-%% RepoPlugins, epm:author(Package), epm:name(Package)),
-%% WithoutDeps = lists:member(without_deps, Package#pkg.args),
-%% Pkgid = #pkgid{ author=Repo#repo.owner
-%% , pkg_name=Repo#repo.name
-%% , vsn=epm:vsn(Package)
-%% },
-%% digraph:add_vertex(G, Pkgid),
-%%
-%% case ParentPkgid of
-%% undefined -> ok;
-%% #pkgid{pkg_name=ParentProjectName} ->
-%% digraph:add_edge(G, ParentPkgid, Pkgid),
-%% case digraph_utils:is_acyclic(G) of
-%% true -> ok;
-%% false -> ?EXIT("circular dependency detected: ~s <--> ~s"
-%% , [ParentProjectName, epm:name(Repo)])
-%% end
-%% end,
-%%
-%% PkgVsn = case epm:vsn(Package) of
-%% undefined -> apply(Repo#repo.api_module, default_vsn, []);
-%% X -> X
-%% end,
-%%
-%% {Deps, Dict1} =
-%% case WithoutDeps of
-%% true ->
-%% {[], Dict};
-%% false ->
-%% Deps0 = apply(Repo#repo.api_module, package_deps
-%% , [epm:name(Repo), PkgVsn]),
-%% F = fun({Dep, Args}, TempDict) ->
-%% {DepName, DepUser} = epm_ops:split_package(Dep),
-%% DepVsn = epm_ops:read_vsn_from_args(
-%% Args, apply(Repo#repo.api_module, default_vsn, [])),
-%% PackageId = #pkgid{author=DepUser, author=DepName, vsn = DepVsn},
-%% Package0 = #pkg{id = PackageId
-%%
-%% , args = Args },
-%% TempDict1 = package_dependencies_internal([Package0], RepoPlugins, G, Pkgid
-%% , TempDict),
-%% {{DepUser, DepName, DepVsn}, TempDict1}
-%% end,
-%% lists:mapfoldl(F, Dict, Deps0)
-%% end,
-%%
-%% NewKey = #pkgid{author=Repo#repo.owner, pkg_name=Repo#repo.name, vsn=PkgVsn},
-%% Package1 = Package#pkg{ id = NewKey
-%% , deps = Deps
-%% , repo = Repo },
-%% package_dependencies_internal(Tail, RepoPlugins, G, ParentPkgid
-%% , dict:store(Pkgid, Package1, Dict1)).
+-spec resolve_dependencies_internal(ordsets:ordset(pkgid())
+ , ordsets:ordset(pkgid()))
+ -> ordsets:ordset(pkgid()).
+resolve_dependencies_internal(Pkgids, Pkgids) -> Pkgids;
+resolve_dependencies_internal(Pkgids, _Previous) ->
+ F = fun(Pkgid=#pkgid{}, A) ->
+ [Pkg] = epm_index:find_package(Pkgid),
+ lists:foldl(fun(Dep, A1) -> ordsets:add_element(Dep, A1) end
+ , A, Pkg#pkg.deps)
+ end,
+ PkgidsPlusDeps = lists:foldl(F, ordsets:from_list(Pkgids), Pkgids),
+ resolve_dependencies_internal(PkgidsPlusDeps, Pkgids).
View
68 src/epm_index.erl
@@ -8,55 +8,81 @@
-module(epm_index).
%% API
--export([ open/2
+-export([open/2
, list_local_packages/0
, list_local_by/3
, delete_local/1
, insert_local/2
- , close/0]).
+ , close/0, find_package/1]).
-include("epm.hrl").
+%-include_lib("stdlib/include/qlc.hrl").
+-include_lib("stdlib/include/ms_transform.hrl").
--define(local_index, epm_local_index).
--define(local_index_file, "epm_local_index").
+%% -define(local_index, epm_local_index).
+%% -define(local_index_file, "epm_local_index").
-define(global_index, epm_index).
--define(global_index_file, "epm_index").
+-define(global_index_file, "epm_packages").
+
+%% -define(global_repo_index, epm_repo_index).
+%% -define(global_repo_index_file, "epm_repos").
%%------------------------------------------------------------------------------
-close() ->
- dets:close(?local_index),
- dets:close(?global_index).
+find_package(#pkgid{ author=A1, pkg_name=N1, platform=P1
+ , vsn=V1, erlang_vsn=E1}) ->
+ Q = ets:fun2ms(fun(#pkg{id=#pkgid{ author=A2, pkg_name=N2, platform=P2
+ , vsn=V2, erlang_vsn=E2}}=Pkg)
+ when (N1 =:= N2
+ andalso (A1 =:= A2 orelse A1 =:= ?any_author)) -> Pkg
+ end),
+ ets:select(?global_index, Q).
+
+close() -> ok.
open(_Home, EpmHome) ->
- LocalIndexFile = ?local_index_file,
- open_dets_file(LocalIndexFile, ?local_index),
+ G1 = open_dets_file(filename:join([EpmHome, ?global_index_file])),
+ ets:new(?global_index, [named_table, {keypos, #pkg.id}]),
+ lists:foreach(fun(X1) -> ets:insert(?global_index, X1) end, G1),
- IndexFile = filename:join([EpmHome, ?global_index_file]),
- open_dets_file(IndexFile , ?global_index),
+ %% Fixtures
+ CowboyId = #pkgid{pkg_name="cowboy"},
+ RanchId = #pkgid{pkg_name="ranch"},
+ GunId = #pkgid{pkg_name="gun"},
+ FwId = #pkgid{pkg_name="farwest"},
+ OtherId = #pkgid{pkg_name="other"},
+ ets:insert(?global_index, #pkg{id=CowboyId, deps=[RanchId]}),
+ ets:insert(?global_index, #pkg{id=RanchId, deps=[GunId]}),
+ ets:insert(?global_index, #pkg{id=GunId}),
+ ets:insert(?global_index, #pkg{id=FwId}),
+ ets:insert(?global_index, #pkg{id=OtherId}),
State = #epm_state{},
State.
list_local_packages() ->
- dets:match(?local_index, '$1').
+ ets:match(?global_index, '$1').
%% @doc Provide '_' if field is not relevant
list_local_by(User, ProjectName, Version) ->
- dets:match(?local_index, {{User, ProjectName, Version}, '$1'}).
+ ets:match(?global_index, {{User, ProjectName, Version}, '$1'}).
delete_local(Key={_User, _Name, _Vsn}) ->
- dets:delete(?local_index, Key).
+ ets:delete(?global_index, Key).
insert_local(Key={_User, _Name, _Vsn}, Package=#pkg{}) ->
- dets:insert(?local_index, {Key, Package}).
+ ets:insert(?global_index, {Key, Package}).
%% @private
-open_dets_file(File, Table) ->
- case dets:open_file(Table, [{type, set}, {file, File}]) of
+open_dets_file(File) ->
+ case dets:open_file(epm_temporary, [{type, set}, {file, File}]) of
{ok, _} -> ok;
{error, {file_error, _, eacces}} ->
- ?EXIT("insufficient access to epm index file: ~s", [File]);
+ ?EPM_FAIL("insufficient access to epm index file: ~s", [File]);
{error, Reason} ->
- ?EXIT("failed to open epm index file (~s): ~p", [File, Reason])
- end.
+ ?EPM_FAIL("failed to open epm index file (~s): ~p", [File, Reason])
+ end,
+ %% Load everything and return, to be inserted to ETS or used later
+ Objects = dets:match(epm_temporary, '$1'),
+ dets:close(epm_temporary),
+ Objects.
View
8 src/epm_ops.erl
@@ -43,9 +43,9 @@ filter_installed_packages([Package|Tail], Installed, NotInstalled) ->
split_package(Raw) -> split_package(Raw, []).
-split_package([], Package) -> {Package, none};
-split_package([47 | Package], User) -> {Package, User};
-split_package([A | Tail], User) -> split_package(Tail, User ++ [A]).
+split_package([], Package) -> {Package, ?any_author};
+split_package([47 | Package], Author) -> {Package, Author};
+split_package([A | Tail], Author) -> split_package(Tail, Author ++ [A]).
installed_packages(_State=#epm_state{}) ->
@@ -84,7 +84,7 @@ dependant_installed_packages(_Package, Acc, []) -> Acc;
dependant_installed_packages(#pkg{}=Package
, Acc
, [[{_, #pkg{deps = Deps} = InstalledPackage}]|Tail]) ->
- F = fun(#pkgid{}=Pkgid) -> epm:equals(Pkgid, Package#pkg.id) end,
+ F = fun(#pkgid{}=Pkgid) -> epm:matches(Pkgid, Package#pkg.id) end,
Acc1 = case lists:filter(F, Deps) of
[] -> Acc;
[_] -> [InstalledPackage|Acc]
View
2  src/epm_util.erl
@@ -84,7 +84,7 @@ epm_home_dir(Home) ->
case file:make_dir(EPM) of
ok -> EPM;
{error, Reason} ->
- ?EXIT("failed to create epm home directory (~s): ~p", [EPM, Reason])
+ ?EPM_FAIL("failed to create epm home directory (~s): ~p", [EPM, Reason])
end
end.
Please sign in to comment.
Something went wrong with that request. Please try again.