From 06cd768dac8af1475b4b73ea2ccc6407de8d2475 Mon Sep 17 00:00:00 2001 From: Dmytro Lytovchenko Date: Sat, 8 Feb 2014 18:21:34 +0100 Subject: [PATCH] reworked indexes, dialyzer --- .gitignore | 3 +- Makefile | 39 ++++++- README.md | 243 +-------------------------------------- README_old.md | 236 +++++++++++++++++++++++++++++++++++++ dialyzer.ignore-warnings | 0 include/epm.hrl | 16 ++- src/epm.erl | 58 ++-------- src/epm_cfg.erl | 77 ++++++++++++- src/epm_core.erl | 192 ++++++++++++------------------- src/epm_deps.erl | 45 ++++---- src/epm_index.erl | 8 +- src/epm_ops.erl | 151 +++++++++++++----------- src/epm_package.erl | 8 +- src/epm_util.erl | 22 ++-- 14 files changed, 569 insertions(+), 529 deletions(-) create mode 100644 README_old.md create mode 100644 dialyzer.ignore-warnings diff --git a/.gitignore b/.gitignore index 2ade584..b546cf6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ deps ebin/* epm *.iml -.idea \ No newline at end of file +.idea +*.plt \ No newline at end of file diff --git a/Makefile b/Makefile index 7dad40d..5ca9a9f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,39 @@ -.PHONY: epm -epm: +.PHONY: compile +compile: rebar get-deps compile escriptize +#------------------------------------------------------------------------------- +OTP_PLT = .epm_otp.plt +COMBO_PLT = .epm_combo.plt +PLT_LIBS0 = ebin $(wildcard deps/*/ebin) +PLT_LIBS = $(subst deps/riak_pb/ebin,,$(PLT_LIBS0)) + +DIALYZER_APPS = epm +DIALYZER_APPS_PATHS = ebin +#$(addsuffix /ebin, $(addprefix apps/, $(DIALYZER_APPS))) + +.PHONY: check_plt +check_plt: $(COMBO_PLT) + dialyzer --check_plt --plt $(COMBO_PLT) $(PLT_LIBS) + +.PHONY: build_sysplt +build_sysplt: $(OTP_PLT) + +$(OTP_PLT): + dialyzer --output_plt $(OTP_PLT) --build_plt \ + --apps erts kernel stdlib inets sasl ssl public_key crypto mnesia + +.PHONY: build_plt +build_plt: compile build_sysplt $(COMBO_PLT) + +$(COMBO_PLT): + dialyzer --plt $(OTP_PLT) --output_plt $(COMBO_PLT) --add_to_plt $(PLT_LIBS) + +.PHONY: dialyze +dialyze: compile check_plt + dialyzer -Wno_return --fullpath --plt $(COMBO_PLT) $(DIALYZER_APPS_PATHS) \ + | fgrep -v -f ./dialyzer.ignore-warnings | tee dialyzer.log - + +.PHONY: cleanplt +cleanplt: + rm $(COMBO_PLT) diff --git a/README.md b/README.md index f1ea4d7..d01f52b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is client/server package manager for prebuilt binary Erlang packages, but with source support. See requirements below. -Project is in development. Do not use. +Project is in development. _Do not use_ ## Requirements @@ -24,243 +24,4 @@ These are things I expect `epm` to be able to do: ### Future Plans -* Store index in Git(hub) with pull-requests and signing - --------------------- - -### epm _IS_ -* an Erlang package manager meant to have _minimal_ impact on projects -* a simple and easy dependency tracker - -### epm _IS NOT_ -* a packaging and deployment tool -* meant to handle non-Erlang dependencies - -### Install - - curl "https://github.com/JacobVorreuter/epm/raw/master/epm" > epm - chmod +x epm - sudo mv epm /usr/local/bin/ - - epm config --set build_dir "/tmp" - epm config --set install_dir "/Users/jvorreuter/erl_libs" - epm config --set proxy_host http://my.corporate.proxy - epm config --set proxy_port 80 - epm config --set net_timeout 60000 # for a slow network... - -### Read the blog post - - - -### Usage - - install [/] {project options}, ... {global options} - project options: - --tag - --branch - --sha - --with-deps (default) - --without-deps - --prebuild-command - --build-command - --test-command - global options: - --verbose - --config-set - - remove [/] {project options}, ... {global options} - project options: - --tag - --branch - --sha - global options: - --verbose - - --config-set - - update [/] {project options}, ... {global options} - project options: - --tag - --branch - --sha - --with-deps - --without-deps (default) - global options: - --verbose - - --config-set - - info [/], ... {global options} - global options: - --config-set - - search , ... {global options} - global options: - --config-set - - list - - latest - - config {options} - options: - --get (default) - --set - --remove - -### Do it - -tell epm where to install packages - - jvorreuter$ epm config --set install_dir /Users/jvorreuter/dev - epm v0.1.1, 2010 - - + updated .epm config - -search for an Erlang app - - jvorreuter$ ./epm search excavator - epm v0.1.1, 2010 - - =============================== - AVAILABLE - =============================== - name: excavator - owner: JacobVorreuter - followers: 7 - homepage: - description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) - tags: - "0.3" - branches: - master - scheduler - -install that app that you wanted (its dependencies will be installed too) - - jvorreuter$ ./epm install excavator - epm v0.1.1, 2010 - - =============================== - Install the following packages? - =============================== - + clones-mochiweb-master - + JacobVorreuter-mochiweb_server_behavior-master - + epm-etap-master - + JacobVorreuter-dynamic_compile-master - + JacobVorreuter-mochixpath-master - + JacobVorreuter-excavator-master - - ([y]/n) y - - + downloading http://github.com/clones/mochiweb/tarball/master - + running mochiweb build command - + running mochiweb install command - + downloading http://github.com/JacobVorreuter/mochiweb_server_behavior/tarball/master - + running mochiweb_server_behavior build command - + running mochiweb_server_behavior install command - + downloading http://github.com/epm/etap/tarball/master - + running etap build command - + running etap install command - + downloading http://github.com/JacobVorreuter/dynamic_compile/tarball/master - + running dynamic_compile build command - + running dynamic_compile install command - + downloading http://github.com/JacobVorreuter/mochixpath/tarball/master - + running mochixpath build command - + running mochixpath install command - + downloading http://github.com/JacobVorreuter/excavator/tarball/master - + running excavator build command - + running excavator install command - -get some info about that app you just installed - - jvorreuter$ ./epm info excavator - epm v0.1.1, 2010 - - =============================== - INSTALLED - =============================== - name: excavator - owner: JacobVorreuter - vsn: master - install dir: /Users/jvorreuter/dev/excavator-0.3 - homepage: - description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) - dependencies: - clones/mochiweb/master - mochixpath/master - dynamic_compile/master - epm/etap/master - mochiweb_server_behavior/master - -how 'bout a list of all apps I've installed? - - jvorreuter$ ./epm list - epm v0.1.1, 2010 - - =============================== - INSTALLED - =============================== - name: excavator - owner: JacobVorreuter - vsn: master - install dir: /Users/jvorreuter/dev/excavator-0.3 - homepage: - description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) - dependencies: - clones/mochiweb/master - mochixpath/master - dynamic_compile/master - epm/etap/master - mochiweb_server_behavior/master - - name: mochixpath - owner: JacobVorreuter - vsn: master - install dir: /Users/jvorreuter/dev/mochixpath-0.1 - homepage: http://yummymeatwhiz.com - description: Mochiweb html parser xpath extension - - name: dynamic_compile - owner: JacobVorreuter - vsn: master - install dir: /Users/jvorreuter/dev/dynamic_compile-0.1 - homepage: - description: compile and load erlang modules from string input - - name: mochiweb_server_behavior - owner: JacobVorreuter - vsn: master - install dir: /Users/jvorreuter/dev/mochiweb_server_behavior-0.1 - homepage: - description: Erlang behavior for a simple mochiweb web server - dependencies: - clones/mochiweb/master - - name: etap - owner: epm - vsn: master - install dir: /Users/jvorreuter/dev/etap-0.3.4 - homepage: - description: etap is a simple erlang testing library that provides TAP compliant output. - - name: mochiweb - owner: clones - vsn: master - install dir: /Users/jvorreuter/dev/mochiweb-0.01 - homepage: http://code.google.com/p/mochiweb/ - description: mochiweb clone - -what have I done? I must remove that terrible app. Its dependencies can stay though - - jvorreuter$ ./epm remove excavator - epm v0.1.1, 2010 - - =============================== - Remove the following packages? - =============================== - + JacobVorreuter-excavator-master - - ([y]/n) y - - + removing package JacobVorreuter-excavator-master from /Users/jvorreuter/dev/excavator-0.3 +* Store index in Git(hub) with pull-requests and signing \ No newline at end of file diff --git a/README_old.md b/README_old.md new file mode 100644 index 0000000..478c879 --- /dev/null +++ b/README_old.md @@ -0,0 +1,236 @@ +### epm _IS_ +* an Erlang package manager meant to have _minimal_ impact on projects +* a simple and easy dependency tracker + +### epm _IS NOT_ +* a packaging and deployment tool +* meant to handle non-Erlang dependencies + +### Install + + curl "https://github.com/JacobVorreuter/epm/raw/master/epm" > epm + chmod +x epm + sudo mv epm /usr/local/bin/ + + epm config --set build_dir "/tmp" + epm config --set install_dir "/Users/jvorreuter/erl_libs" + epm config --set proxy_host http://my.corporate.proxy + epm config --set proxy_port 80 + epm config --set net_timeout 60000 # for a slow network... + +### Read the blog post + + + +### Usage + + install [/] {project options}, ... {global options} + project options: + --tag + --branch + --sha + --with-deps (default) + --without-deps + --prebuild-command + --build-command + --test-command + global options: + --verbose + --config-set + + remove [/] {project options}, ... {global options} + project options: + --tag + --branch + --sha + global options: + --verbose + + --config-set + + update [/] {project options}, ... {global options} + project options: + --tag + --branch + --sha + --with-deps + --without-deps (default) + global options: + --verbose + + --config-set + + info [/], ... {global options} + global options: + --config-set + + search , ... {global options} + global options: + --config-set + + list + + latest + + config {options} + options: + --get (default) + --set + --remove + +### Do it + +tell epm where to install packages + + jvorreuter$ epm config --set install_dir /Users/jvorreuter/dev + epm v0.1.1, 2010 + + + updated .epm config + +search for an Erlang app + + jvorreuter$ ./epm search excavator + epm v0.1.1, 2010 + + =============================== + AVAILABLE + =============================== + name: excavator + owner: JacobVorreuter + followers: 7 + homepage: + description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) + tags: + "0.3" + branches: + master + scheduler + +install that app that you wanted (its dependencies will be installed too) + + jvorreuter$ ./epm install excavator + epm v0.1.1, 2010 + + =============================== + Install the following packages? + =============================== + + clones-mochiweb-master + + JacobVorreuter-mochiweb_server_behavior-master + + epm-etap-master + + JacobVorreuter-dynamic_compile-master + + JacobVorreuter-mochixpath-master + + JacobVorreuter-excavator-master + + ([y]/n) y + + + downloading http://github.com/clones/mochiweb/tarball/master + + running mochiweb build command + + running mochiweb install command + + downloading http://github.com/JacobVorreuter/mochiweb_server_behavior/tarball/master + + running mochiweb_server_behavior build command + + running mochiweb_server_behavior install command + + downloading http://github.com/epm/etap/tarball/master + + running etap build command + + running etap install command + + downloading http://github.com/JacobVorreuter/dynamic_compile/tarball/master + + running dynamic_compile build command + + running dynamic_compile install command + + downloading http://github.com/JacobVorreuter/mochixpath/tarball/master + + running mochixpath build command + + running mochixpath install command + + downloading http://github.com/JacobVorreuter/excavator/tarball/master + + running excavator build command + + running excavator install command + +get some info about that app you just installed + + jvorreuter$ ./epm info excavator + epm v0.1.1, 2010 + + =============================== + INSTALLED + =============================== + name: excavator + owner: JacobVorreuter + vsn: master + install dir: /Users/jvorreuter/dev/excavator-0.3 + homepage: + description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) + dependencies: + clones/mochiweb/master + mochixpath/master + dynamic_compile/master + epm/etap/master + mochiweb_server_behavior/master + +how 'bout a list of all apps I've installed? + + jvorreuter$ ./epm list + epm v0.1.1, 2010 + + =============================== + INSTALLED + =============================== + name: excavator + owner: JacobVorreuter + vsn: master + install dir: /Users/jvorreuter/dev/excavator-0.3 + homepage: + description: An Erlang application for ingesting data from various sources (APIs, data feeds, web content, etc) + dependencies: + clones/mochiweb/master + mochixpath/master + dynamic_compile/master + epm/etap/master + mochiweb_server_behavior/master + + name: mochixpath + owner: JacobVorreuter + vsn: master + install dir: /Users/jvorreuter/dev/mochixpath-0.1 + homepage: http://yummymeatwhiz.com + description: Mochiweb html parser xpath extension + + name: dynamic_compile + owner: JacobVorreuter + vsn: master + install dir: /Users/jvorreuter/dev/dynamic_compile-0.1 + homepage: + description: compile and load erlang modules from string input + + name: mochiweb_server_behavior + owner: JacobVorreuter + vsn: master + install dir: /Users/jvorreuter/dev/mochiweb_server_behavior-0.1 + homepage: + description: Erlang behavior for a simple mochiweb web server + dependencies: + clones/mochiweb/master + + name: etap + owner: epm + vsn: master + install dir: /Users/jvorreuter/dev/etap-0.3.4 + homepage: + description: etap is a simple erlang testing library that provides TAP compliant output. + + name: mochiweb + owner: clones + vsn: master + install dir: /Users/jvorreuter/dev/mochiweb-0.01 + homepage: http://code.google.com/p/mochiweb/ + description: mochiweb clone + +what have I done? I must remove that terrible app. Its dependencies can stay though + + jvorreuter$ ./epm remove excavator + epm v0.1.1, 2010 + + =============================== + Remove the following packages? + =============================== + + JacobVorreuter-excavator-master + + ([y]/n) y + + + removing package JacobVorreuter-excavator-master from /Users/jvorreuter/dev/excavator-0.3 diff --git a/dialyzer.ignore-warnings b/dialyzer.ignore-warnings new file mode 100644 index 0000000..e69de29 diff --git a/include/epm.hrl b/include/epm.hrl index 26c4672..6c33055 100644 --- a/include/epm.hrl +++ b/include/epm.hrl @@ -5,7 +5,14 @@ -define(EXIT(Format, Args), exit(lists:flatten(io_lib:format(Format, Args)))). --record(repository, { name +%% State of the application, contains loaded local index, installed apps and +%% remote index +-record(epm_state, { local_available = [] + , installed = [] + , remote_available = [] + }). + +-record(epm_repo, { name , owner , description , homepage @@ -13,12 +20,13 @@ , pushed , api_module }). --record(package, {user + +-record(epm_package, {user , name , vsn=undefined , app_vsn , install_dir , deps=[] , args=[] - , repo=#repository{} - }). \ No newline at end of file + , repo=#epm_repo{} + }). diff --git a/src/epm.erl b/src/epm.erl index cf5053a..a4a0b05 100644 --- a/src/epm.erl +++ b/src/epm.erl @@ -20,54 +20,14 @@ main(Args) -> io:format("~n"). main_internal(Args) -> + epm_cfg:init(), Home = epm_util:home_dir(), EpmHome = epm_util:epm_home_dir(Home), - epm_util:open(Home, EpmHome), - - %% consult global .epm config file in home directory - case file:path_consult(["."] ++ Home ++ [code:root_dir()], ".epm") of - {ok, [GlobalConfig], FileLoc} -> - - epm_cfg:init(GlobalConfig), - epm_cfg:set(global_config, FileLoc), - epm_cfg:set(vsn, ?epm_version), - io:format("epm v~s, ~p~n~n", [?epm_version, ?epm_year]), - - case proplists:get_value(install_dir, GlobalConfig) of - undefined -> - io:format("################ Warning ################~n"), - io:format("You have not specified a value for ~n"), - io:format("install_dir in your .epm config file. The~n"), - io:format("current working directory will be used.~n~n"), - io:format("run `epm config --set install_dir `~n"), - io:format("#########################################~n~n"), - ok; - InstallDir -> epm_util:add_to_path(InstallDir) - end, - - setup_connectivity(GlobalConfig), - - epm_core:execute(GlobalConfig, Args); - {ok, [], FileLoc} -> - epm_cfg:init([]), - epm_cfg:set(global_config, FileLoc), - epm_core:execute([], Args); - {error, enoent} -> - file:write_file(filename:join([Home, ".epm"]), <<>>), - epm_cfg:init([]), - epm_cfg:set(global_config, filename:join([Home, ".epm"])), - epm_core:execute([], Args); - {error, Reason} -> - ?EXIT("failed to read epm global config: ~p", [Reason]) - end. - -setup_connectivity(GlobalConfig) -> - case proplists:get_value(proxy_host, GlobalConfig) of - undefined -> - epm_util:set_http_proxy(none, none); - Host -> - Port = proplists:get_value(proxy_port, GlobalConfig, "8080"), - epm_util:set_http_proxy(Host, Port) - end, - Timeout = proplists:get_value(net_timeout, GlobalConfig, 6000), - epm_util:set_net_timeout(Timeout). + State = epm_index:open(Home, EpmHome), + setup_connectivity(), + epm_core:execute(State, Args). + +setup_connectivity() -> + epm_util:set_http_proxy( epm_cfg:get(proxy_host, none) + , epm_cfg:get(proxy_port, none)), + epm_util:set_net_timeout(epm_cfg:get(net_timeout, 6000)). diff --git a/src/epm_cfg.erl b/src/epm_cfg.erl index 4ec17f4..a509722 100644 --- a/src/epm_cfg.erl +++ b/src/epm_cfg.erl @@ -7,13 +7,48 @@ -module(epm_cfg). %% API --export([init/1, set/2, get/1, get/2]). +-export([init/0 + , set/2 + , get/1 + , get/2 + , get_all/0 + , print_config_values/0, write_config_file/0, delete/1]). +-include("epm.hrl"). -define(cfg_table, epm_cfg). -init(Config) -> +init() -> ets:new(?cfg_table, [named_table]), - lists:foreach(fun({K, V}) -> set(K, V) end, Config). + + Home = epm_util:home_dir(), + set(vsn, ?epm_version), + + %% consult global .epm config file in home directory + GlobalConfig = + case file:path_consult(["."] ++ Home ++ [code:root_dir()], ".epm") of + {ok, [C], _FileLoc} -> + io:format("epm v~s, ~p~n~n", [?epm_version, ?epm_year]), + + case proplists:get_value(install_dir, C) of + undefined -> + io:format("################ Warning ################~n"), + io:format("You have not specified a value for ~n"), + io:format("install_dir in your .epm config file. The~n"), + io:format("current working directory will be used.~n~n"), + io:format("run `epm config --set install_dir `~n"), + io:format("#########################################~n~n"), + ok; + InstallDir -> epm_util:add_to_path(InstallDir) + end, + C; + {ok, [], _FileLoc} -> []; + {error, enoent} -> + file:write_file(filename:join([Home, ".epm"]), <<>>), + []; + {error, Reason} -> + ?EXIT("failed to read epm global config: ~p", [Reason]) + end, + lists:foreach(fun({K, V}) -> set(K, V) end, GlobalConfig). set(Key, Value) -> ets:insert(?cfg_table, {Key, Value}). @@ -24,8 +59,44 @@ get(Key) -> [{Key, Value}] -> {ok, Value} end. +delete(Key) -> + ets:delete(?cfg_table, Key). + get(Key, Default) -> case ets:lookup(?cfg_table, Key) of [] -> Default; [{Key, Value}] -> Value end. + +get_all() -> + ets:tab2list(?cfg_table). + +%% ----------------------------------------------------------------------------- +%% Global Config +%% ----------------------------------------------------------------------------- +print_config_values() -> + [io:format("~p\t\t~p~n", [K,V]) || {K,V} <- epm_cfg:get_all()]. + +write_config_file() -> + {ok, FileLoc} = epm_cfg:get(global_config), + case file:open(FileLoc, [write]) of + {ok, IoDevice} -> + io:format(IoDevice, "[~n", []), + F = fun({Key, Val}, Count) -> + if Count == 0 -> ok; + true -> io:format(IoDevice, ",~n", []) + end, + case {Key, Val} of + {repo_plugins, [C|_]} when is_integer(C) -> + io:format(IoDevice, " {~p, ~s}", [Key, Val]); + _ -> + io:format(IoDevice, " {~p, ~p}", [Key, Val]) + end, + Count + 1 + end, + lists:foldl(F, 0, get_all()), + io:format(IoDevice, "~n].~n", []), + io:format("+ updated .epm config~n"); + {error, Reason} -> + ?EXIT("failed to update .epm config (~s): ~p", [FileLoc, Reason]) + end. \ No newline at end of file diff --git a/src/epm_core.erl b/src/epm_core.erl index 124ee86..5252f09 100644 --- a/src/epm_core.erl +++ b/src/epm_core.erl @@ -3,10 +3,10 @@ -include("epm.hrl"). -execute(GlobalConfig0, ["install" | Args]) -> - {GlobalConfig, Packages, Flags} = collect_args(install, Args, GlobalConfig0), +execute(State=#epm_state{}, ["install" | Args]) -> + {Packages, Flags} = collect_args(install, Args), epm_cfg:set(verbose, lists:member(verbose, Flags)), - Deps = epm_deps:package_dependencies(GlobalConfig, Packages), + Deps = epm_deps:package_dependencies(Packages), {Installed, NotInstalled} = epm_ops:filter_installed_packages(Deps), case NotInstalled of [] -> @@ -18,26 +18,26 @@ execute(GlobalConfig0, ["install" | Args]) -> io:format("===============================~n"), io:format("Packages already installed:~n"), io:format("===============================~n"), - [begin - io:format(" + ~s-~s-~s (~s)~n", [U, N, V, AppVsn]) - end || #package{user = U, name = N, vsn = V, app_vsn = AppVsn} <- Installed] + [io:format(" + ~s-~s-~s (~s)~n", [U, N, V, AppVsn]) + || #epm_package{user = U, name = N, vsn = V, app_vsn = AppVsn} <- Installed] end, io:format("===============================~n"), io:format("Install the following packages?~n"), io:format("===============================~n"), - [io:format(" + ~s-~s-~s~n", [U, N, V]) || #package{user = U, name = N, vsn = V} <- NotInstalled], + [io:format(" + ~s-~s-~s~n", [U, N, V]) + || #epm_package{user = U, name = N, vsn = V} <- NotInstalled], io:format("~n([y]/n) "), case io:get_chars("", 1) of C when C == "y"; C == "\n" -> io:format("~n"), - [epm_ops:install_package(GlobalConfig, Package) - || Package <- NotInstalled]; + lists:foldl(fun(X, St) -> epm_ops:install_package(St, X) end + , State, NotInstalled); _ -> ok end end; -execute(GlobalConfig0, ["remove" | Args]) -> - {GlobalConfig, Packages, Flags} = collect_args(remove, Args, GlobalConfig0), +execute(State=#epm_state{}, ["remove" | Args]) -> + {Packages, Flags} = collect_args(remove, Args), epm_cfg:set(verbose, lists:member(verbose, Flags)), Installed = epm_ops:get_installed_packages(Packages), case Installed of @@ -48,19 +48,19 @@ execute(GlobalConfig0, ["remove" | Args]) -> io:format("Remove the following packages?~n"), io:format("===============================~n"), [io:format(" + ~s-~s-~s~n", [U, N, V]) - || #package{user = U, name = N, vsn = V} <- Installed], + || #epm_package{user = U, name = N, vsn = V} <- Installed], io:format("~n([y]/n) "), case io:get_chars("", 1) of C when C == "y"; C == "\n" -> io:format("~n"), - [epm_ops:remove_package(GlobalConfig, Package) - || Package <- Installed]; + lists:foldl(fun(X, St) -> epm_ops:remove_package(St, X) end + , State, Installed); _ -> ok end end; -execute(GlobalConfig0, ["update" | Args]) -> - {GlobalConfig, Packages, Flags} = collect_args(update, Args, GlobalConfig0), +execute(State=#epm_state{}, ["update" | Args]) -> + {Packages, Flags} = collect_args(update, Args), epm_cfg:set(verbose, lists:member(verbose, Flags)), Installed = epm_ops:get_installed_packages(Packages), case Installed of @@ -71,19 +71,19 @@ execute(GlobalConfig0, ["update" | Args]) -> io:format("Update the following packages?~n"), io:format("===============================~n"), [io:format(" + ~s-~s-~s~n", [U, N, V]) - || #package{user = U, name = N, vsn = V} <- Installed], + || #epm_package{user = U, name = N, vsn = V} <- Installed], io:format("~n([y]/n) "), case io:get_chars("", 1) of C when C == "y"; C == "\n" -> io:format("~n"), - [epm_ops:update_package(GlobalConfig, Package) - || Package <- Installed]; + lists:foldl(fun(X, St) -> epm_ops:update_package(St, X) end + , State, Installed); _ -> ok end end; -execute(GlobalConfig0, ["info" | Args]) -> - {GlobalConfig, Packages, _Flags} = collect_args(info, Args, GlobalConfig0), +execute(State=#epm_state{}, ["info" | Args]) -> + {Packages, _Flags} = collect_args(info, Args), {Installed, NotInstalled} = epm_ops:filter_installed_packages(Packages), case Installed of [] -> ok; @@ -100,7 +100,7 @@ execute(GlobalConfig0, ["info" | Args]) -> end, epm_ops:print_installed_package_info(Package), Count + 1 - end , 0, lists:reverse(Installed)) + end, 0, lists:reverse(Installed)) end, case NotInstalled of @@ -110,17 +110,15 @@ execute(GlobalConfig0, ["info" | Args]) -> [] -> ok; _ -> io:format("~n") end, - epm_ops:print_not_installed_package_info(GlobalConfig - , NotInstalled, true) + epm_ops:print_not_installed_package_info(State, NotInstalled, true) end; -execute(GlobalConfig0, ["search" | Args]) -> - {GlobalConfig, Packages, _Flags} = collect_args(search, Args, GlobalConfig0), - epm_ops:print_not_installed_package_info(GlobalConfig - , lists:reverse(Packages)); +execute(State=#epm_state{}, ["search" | Args]) -> + {Packages, _Flags} = collect_args(search, Args), + epm_ops:print_not_installed_package_info(State, lists:reverse(Packages)); -execute(_GlobalConfig, ["list" | _Args]) -> - Installed = epm_ops:installed_packages(), +execute(State=#epm_state{}, ["list" | _Args]) -> + Installed = epm_ops:installed_packages(State), case Installed of [] -> io:format("- no packages installed~n"); @@ -129,45 +127,37 @@ execute(_GlobalConfig, ["list" | _Args]) -> io:format("INSTALLED~n"), io:format("===============================~n"), - lists:foldl( - fun(Package, Count) -> + F = fun(Package, Count) -> case Count of 0 -> ok; _ -> io:format("~n") end, epm_ops:print_installed_package_info(Package), Count + 1 - end , 0, lists:reverse(Installed)) + end, + lists:foldl(F, 0, lists:reverse(Installed)) end; -execute(_GlobalConfig, ["latest" | _Args]) -> - update_epm(); +execute(State=#epm_state{}, ["latest" | _Args]) -> + update_epm(State); -execute(GlobalConfig0, ["config" | Args]) -> - {GlobalConfig, _Packages, Flags} = collect_args(config, Args, GlobalConfig0), +execute(_State=#epm_state{}, ["config" | Args]) -> + {_Packages, Flags} = collect_args(config, Args), case Flags of [] -> - print_config_values(GlobalConfig); + epm_cfg:print_config_values(); [get] -> - print_config_values(GlobalConfig); + epm_cfg:print_config_values(); _ -> - Config2 = lists:foldl( - fun(Flag, Config) -> - case Flag of - {set, [K, V]} -> - K1 = list_to_atom(K), - [{K1, V}|proplists:delete(K1, Config)]; - {remove, K} -> - K1 = list_to_atom(K), - proplists:delete(K1, Config); - _ -> - Config - end - end , GlobalConfig, Flags), - write_config_file(Config2) + F = fun({set, [K, V]}) -> epm_cfg:set(K, V); + ({remove, K}) -> epm_cfg:delete(K); + (_) -> ok + end, + _ = lists:foreach(F, Flags), + epm_cfg:write_config_file() end; -execute(_, _) -> +execute(_State=#epm_state{}, _) -> io:format("Usage: epm commands~n~n"), io:format(" install [/] {project options}, ... {global options}~n"), io:format(" project options:~n"), @@ -225,27 +215,28 @@ execute(_, _) -> %%` GlobalConfig = list() %% Results = {[package(), Flags]} %% Flags = [atom()] -collect_args(Target, Args, GlobalConfig) -> - collect_args(Target, Args, GlobalConfig, [], []). -collect_args(_, [], GlobalConfig, Packages, Flags) -> - {GlobalConfig, lists:reverse(Packages), lists:reverse(Flags)}; -collect_args(Target, [Arg | Rest], GlobalConfig, Packages, Flags) -> +collect_args(Target, Args) -> + collect_args_internal(Target, Args, [], []). + +collect_args_internal(_, [], Packages, Flags) -> + {lists:reverse(Packages), lists:reverse(Flags)}; +collect_args_internal(Target, [Arg | Rest], Packages, Flags) -> case parse_tag(Target, Arg) of undefined -> %% if not a tag then must be a project name %% split into user and project {ProjectName, User} = epm_ops:split_package(Arg), - collect_args(Target, Rest, GlobalConfig - , [#package{user = User, name = ProjectName}|Packages] - , Flags); + collect_args_internal(Target, Rest + , [#epm_package{user = User, name = ProjectName}|Packages] + , Flags); {Type, Tag, 0} -> %% tag with no trailing value case Type of project -> - [#package{args = Args} = Package|OtherPackages] = Packages, - collect_args(Target, Rest, GlobalConfig - , [Package#package{args = Args ++ [Tag]}|OtherPackages] - , Flags); + [#epm_package{args = Args} = Package|OtherPackages] = Packages, + collect_args_internal(Target, Rest + , [Package#epm_package{args = Args ++ [Tag]}|OtherPackages] + , Flags); global -> - collect_args(Target, Rest, GlobalConfig, Packages, [Tag|Flags]) + collect_args_internal(Target, Rest, Packages, [Tag|Flags]) end; {Type, Tag, NumVals} when is_integer(NumVals) -> % tag with trailing value(s) if @@ -262,30 +253,27 @@ collect_args(Target, [Arg | Rest], GlobalConfig, Packages, Flags) -> case Type of project -> %% this tag applies to the last project on the stack - [#package{args = Args} = Package|OtherPackages] = Packages, + [#epm_package{args = Args} = Package|OtherPackages] = Packages, Vsn = if Tag == tag; Tag == branch; Tag == sha -> Vals1; - true -> Package#package.vsn + true -> Package#epm_package.vsn end, - collect_args( Target, Rest1, GlobalConfig - , [Package#package{ vsn = Vsn + collect_args_internal( Target, Rest1 + , [Package#epm_package{ vsn = Vsn , args = Args ++ [{Tag, Vals1}] } | OtherPackages] , Flags); global -> - GlobalConfig1 = - if - Tag == config_set -> - [K, V1] = Vals1, - K1 = list_to_atom(K), - [case K1 of - repo_plugins -> {K1, epm_util:eval(V1 ++ ".")}; - _ -> {K1, V1} - end |proplists:delete(K1, GlobalConfig)]; - true -> - GlobalConfig - end, - collect_args(Target, Rest1, GlobalConfig1, Packages, [{Tag, Vals1}|Flags]) + if Tag == config_set -> + [K, V1] = Vals1, + K1 = list_to_atom(K), + case K1 of + repo_plugins -> epm_cfg:set(K1, epm_util:eval(V1 ++ ".")); + _ -> ok + end; + true -> ok + end, + collect_args_internal(Target, Rest1, Packages, [{Tag, Vals1}|Flags]) end end. @@ -319,13 +307,13 @@ parse_tag(_, _) -> undefined. %% ----------------------------------------------------------------------------- %% Replace epm script with most recent %% ----------------------------------------------------------------------------- -update_epm() -> +update_epm(_State) -> File = case os:find_executable("epm") of false -> case filelib:is_regular("epm") of - true -> "./epm"; - fasle -> exit("failed to find epm executable to replace") + true -> "./epm"; + false -> exit("failed to find epm executable to replace") end; F -> F end, @@ -343,37 +331,7 @@ update_epm() -> exit("failed to download latest version of epm") end. -%% ----------------------------------------------------------------------------- -%% Global Config -%% ----------------------------------------------------------------------------- -print_config_values(GlobalConfig) -> - [io:format("~p\t\t~p~n", [K,V]) || {K,V} <- GlobalConfig]. -write_config_file(GlobalConfig) -> - {ok, FileLoc} = epm_cfg:get(global_config), - case file:open(FileLoc, [write]) of - {ok, IoDevice} -> - io:format(IoDevice, "[~n", []), - lists:foldl( - fun({Key, Val}, Count) -> - if - Count == 0 -> ok; - true -> - io:format(IoDevice, ",~n", []) - end, - case {Key, Val} of - {repo_plugins, [C|_]} when is_integer(C) -> - io:format(IoDevice, " {~p, ~s}", [Key, Val]); - _ -> - io:format(IoDevice, " {~p, ~p}", [Key, Val]) - end, - Count + 1 - end, 0, GlobalConfig), - io:format(IoDevice, "~n].~n", []), - io:format("+ updated .epm config~n"); - {error, Reason} -> - ?EXIT("failed to update .epm config (~s): ~p", [FileLoc, Reason]) - end. %% build_project(GlobalConfig, Package) -> %% ProjectName = (Package#package.repo)#repository.name, diff --git a/src/epm_deps.erl b/src/epm_deps.erl index f857e9e..245f504 100644 --- a/src/epm_deps.erl +++ b/src/epm_deps.erl @@ -7,30 +7,29 @@ -module(epm_deps). %% API --export([package_dependencies/2]). +-export([package_dependencies/1]). -include("epm.hrl"). %% ----------------------------------------------------------------------------- %% Compile list of dependencies %% ----------------------------------------------------------------------------- -package_dependencies(GlobalConfig, Packages) -> - RepoPlugins = proplists:get_value(repo_plugins, GlobalConfig - , ?DEFAULT_API_MODULES), +package_dependencies(Packages) -> + RepoPlugins = epm_cfg:get(repo_plugins, ?DEFAULT_API_MODULES), G = digraph:new(), - UpdatedPackages = package_dependencies1(Packages, RepoPlugins, G, undefined - , 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]. %% @private -package_dependencies1([], _, _, _, Dict) -> Dict; -package_dependencies1([Package|Tail], RepoPlugins, G, Parent, Dict) -> +package_dependencies_internal([], _, _, _, Dict) -> Dict; +package_dependencies_internal([Package|Tail], RepoPlugins, G, Parent, Dict) -> Repo = epm_ops:retrieve_remote_repo( - RepoPlugins, Package#package.user, Package#package.name), - WithoutDeps = lists:member(without_deps, Package#package.args), - Key = {Repo#repository.owner, Repo#repository.name, Package#package.vsn}, + RepoPlugins, Package#epm_package.user, Package#epm_package.name), + WithoutDeps = lists:member(without_deps, Package#epm_package.args), + Key = {Repo#epm_repo.owner, Repo#epm_repo.name, Package#epm_package.vsn}, digraph:add_vertex(G, Key), @@ -41,14 +40,14 @@ package_dependencies1([Package|Tail], RepoPlugins, G, Parent, Dict) -> case digraph_utils:is_acyclic(G) of true -> ok; false -> ?EXIT("circular dependency detected: ~s <--> ~s" - , [ParentProjectName, Repo#repository.name]) + , [ParentProjectName, Repo#epm_repo.name]) end end, PkgVsn = - case Package#package.vsn of - undefined -> apply(Repo#repository.api_module, default_vsn, []); - _ -> Package#package.vsn + case Package#epm_package.vsn of + undefined -> apply(Repo#epm_repo.api_module, default_vsn, []); + _ -> Package#epm_package.vsn end, {Deps, Dict1} = @@ -56,27 +55,27 @@ package_dependencies1([Package|Tail], RepoPlugins, G, Parent, Dict) -> true -> {[], Dict}; false -> - Deps0 = apply(Repo#repository.api_module, package_deps - , [Repo#repository.owner, Repo#repository.name, PkgVsn]), + Deps0 = apply(Repo#epm_repo.api_module, package_deps + , [Repo#epm_repo.owner, Repo#epm_repo.name, PkgVsn]), F = fun({Dep, Args}, TempDict) -> {DepName, DepUser} = epm_ops:split_package(Dep), DepVsn = epm_ops:read_vsn_from_args( - Args, apply(Repo#repository.api_module, default_vsn, [])), - Package0 = #package{user = DepUser + Args, apply(Repo#epm_repo.api_module, default_vsn, [])), + Package0 = #epm_package {user = DepUser , name = DepName , vsn = DepVsn , args = Args }, - TempDict1 = package_dependencies1([Package0], RepoPlugins, G, Key + TempDict1 = package_dependencies_internal([Package0], RepoPlugins, G, Key , TempDict), {{DepUser, DepName, DepVsn}, TempDict1} end, lists:mapfoldl(F, Dict, Deps0) end, - Package1 = Package#package{ user = Repo#repository.owner - , name = Repo#repository.name + Package1 = Package#epm_package{ user = Repo#epm_repo.owner + , name = Repo#epm_repo.name , vsn = PkgVsn , deps = Deps , repo = Repo }, - package_dependencies1(Tail, RepoPlugins, G, Parent + package_dependencies_internal(Tail, RepoPlugins, G, Parent , dict:store(Key, Package1, Dict1)). diff --git a/src/epm_index.erl b/src/epm_index.erl index 63485b1..178feba 100644 --- a/src/epm_index.erl +++ b/src/epm_index.erl @@ -37,7 +37,7 @@ open(Home, EpmHome) -> dets:close(?local_index), [{{User, Name, Vsn} - , #package{user = User + , #epm_package{user = User , name = Name , vsn = Vsn , install_dir = InstallDir @@ -60,7 +60,9 @@ open(Home, EpmHome) -> ?EXIT("insufficient access to epm index file: ~s", [File]); {error, Reason} -> ?EXIT("failed to open epm index file (~s): ~p", [File, Reason]) - end. + end, + State = #epm_state{}, + State. list_local_packages() -> dets:match(?local_index, '$1'). @@ -72,5 +74,5 @@ list_local_by(User, ProjectName, Version) -> delete_local(Key={_User, _Name, _Vsn}) -> dets:delete(?local_index, Key). -insert_local(Key={_User, _Name, _Vsn}, Package=#package{}) -> +insert_local(Key={_User, _Name, _Vsn}, Package=#epm_package{}) -> dets:insert(?local_index, {Key, Package}). diff --git a/src/epm_ops.erl b/src/epm_ops.erl index 2c23f08..4a05a1a 100644 --- a/src/epm_ops.erl +++ b/src/epm_ops.erl @@ -10,12 +10,13 @@ -export([filter_installed_packages/1 , retrieve_remote_repo/3 , retrieve_remote_repos/4 - , installed_packages/0 + , installed_packages/1 , get_installed_packages/1 , split_package/1 , read_vsn_from_args/2 - , print_not_installed_package_info/2 , print_installed_package_info/1 + , print_not_installed_package_info/2 + , print_not_installed_package_info/3 , update_package/2 , remove_package/2 , install_package/2 @@ -44,7 +45,7 @@ split_package([47 | Package], User) -> {Package, User}; split_package([A | Tail], User) -> split_package(Tail, User ++ [A]). -installed_packages() -> +installed_packages(_State=#epm_state{}) -> [Package || [{_,Package}] <- epm_index:list_local_packages()]. get_installed_packages(Packages) -> @@ -61,9 +62,9 @@ installed_packages_internal([Package|Tail], Dict) -> Dict; List -> FoldF = fun(InstalledPackage, TempDict) -> - NewValue = { InstalledPackage#package.user - , InstalledPackage#package.name - , InstalledPackage#package.vsn }, + NewValue = { InstalledPackage#epm_package.user + , InstalledPackage#epm_package.name + , InstalledPackage#epm_package.vsn }, TempDict1 = dict:store(NewValue, InstalledPackage, TempDict), DependantPackages = dependant_installed_packages(InstalledPackage), installed_packages_internal(DependantPackages, TempDict1) @@ -77,11 +78,11 @@ dependant_installed_packages(Package) -> dependant_installed_packages(Package, [], epm_index:list_local_packages()). dependant_installed_packages(_Package, Acc, []) -> Acc; -dependant_installed_packages(#package{user = User +dependant_installed_packages(#epm_package {user = User , name = Name , vsn = Vsn} = Package , Acc - , [[{_, #package{deps = Deps} = InstalledPackage}]|Tail]) -> + , [[{_, #epm_package{deps = Deps} = InstalledPackage}]|Tail]) -> F = fun({U, N, V}) -> (U == User orelse U == none) andalso (N == Name) andalso @@ -102,7 +103,7 @@ retrieve_remote_repo([Module|Tail], none, ProjectName) -> [] -> retrieve_remote_repo(Tail, none, ProjectName); Repos when is_list(Repos) -> - case lists:filter(fun(R1) -> R1#repository.name == ProjectName end + case lists:filter(fun(R1) -> R1#epm_repo.name == ProjectName end , Repos) of [R0|_] -> R0; [] -> retrieve_remote_repo(Tail, none, ProjectName) @@ -113,7 +114,7 @@ retrieve_remote_repo([Module|Tail], none, ProjectName) -> retrieve_remote_repo([Module|Tail], User, ProjectName) -> case apply(Module, info, [User, ProjectName]) of - Repo when is_record(Repo, repository) -> + Repo when is_record(Repo, epm_repo) -> Repo; undefined -> retrieve_remote_repo(Tail, User, ProjectName); @@ -131,7 +132,7 @@ retrieve_remote_repos([Module|Tail], none, ProjectName, IsExact, Acc) -> [] -> retrieve_remote_repos(Tail, none, ProjectName, IsExact, Acc); Repos when is_list(Repos), IsExact == true -> - case lists:filter(fun(R1) -> R1#repository.name == ProjectName end + case lists:filter(fun(R1) -> R1#epm_repo.name == ProjectName end , Repos) of [] -> retrieve_remote_repos(Tail, none, ProjectName, IsExact, Acc); R0s -> @@ -147,7 +148,7 @@ retrieve_remote_repos([Module|Tail], none, ProjectName, IsExact, Acc) -> retrieve_remote_repos([Module|Tail], User, ProjectName, IsExact, Acc) -> case apply(Module, info, [User, ProjectName]) of - Repo when is_record(Repo, repository) -> + Repo when is_record(Repo, epm_repo) -> retrieve_remote_repos(Tail, User, ProjectName, IsExact, Acc ++ [Repo]); undefined -> retrieve_remote_repos(Tail, User, ProjectName, IsExact, Acc); @@ -159,28 +160,29 @@ retrieve_remote_repos([Module|Tail], User, ProjectName, IsExact, Acc) -> %% package info %% ----------------------------------------------------------------------------- %% @private -local_package_info(#package{ user = none +-spec local_package_info(#epm_package{}) -> list(). +local_package_info(#epm_package{ user = none , name = ProjectName , vsn = undefined}) -> case epm_index:list_local_by('_', ProjectName, '_') of [] -> []; List -> [Package || [Package] <- List] end; -local_package_info(#package{ user = none +local_package_info(#epm_package{ user = none , name = ProjectName , vsn = Vsn}) -> case epm_index:list_local_by('_', ProjectName, Vsn) of [] -> []; List -> [Package || [Package] <- List] end; -local_package_info(#package{ user = User +local_package_info(#epm_package{ user = User , name = ProjectName , vsn = undefined}) -> case epm_index:list_local_by(User, ProjectName, '_') of [] -> []; List -> [Package || [Package] <- List] end; -local_package_info(#package{ user = User +local_package_info(#epm_package{ user = User , name = ProjectName , vsn = Vsn}) -> case epm_index:list_local_by(User, ProjectName, Vsn) of @@ -201,18 +203,19 @@ read_vsn_from_args([], Default) -> Default. %% ----------------------------------------------------------------------------- %% Print package info %% ----------------------------------------------------------------------------- +-spec print_installed_package_info(#epm_package{}) -> any(). print_installed_package_info(Package) -> - Repo = Package#package.repo, + Repo = Package#epm_package.repo, [io:format(" ~s: ~s~n", [Field, if Value==undefined -> ""; true -> Value end]) || {Field, Value} <- [ - {"name", Repo#repository.name}, - {"owner", Repo#repository.owner}, - {"vsn", Package#package.vsn}, - {"pushed", Repo#repository.pushed}, - {"install dir", Package#package.install_dir}, - {"homepage", Repo#repository.homepage}, - {"description", Repo#repository.description} + {"name", Repo#epm_repo.name}, + {"owner", Repo#epm_repo.owner}, + {"vsn", Package#epm_package.vsn}, + {"pushed", Repo#epm_repo.pushed}, + {"install dir", Package#epm_package.install_dir}, + {"homepage", Repo#epm_repo.homepage}, + {"description", Repo#epm_repo.description} ]], - case Package#package.deps of + case Package#epm_package.deps of [] -> ok; Deps -> io:format(" dependencies: ~n ~s~n", [string:join([ @@ -222,14 +225,14 @@ print_installed_package_info(Package) -> end || {U,N,V} <- Deps], "\n ")]) end. -print_not_installed_package_info(GlobalConfig, Packages) -> - print_not_installed_package_info(GlobalConfig, Packages, false). +print_not_installed_package_info(State=#epm_state{}, Packages) -> + print_not_installed_package_info(State, Packages, false). -print_not_installed_package_info(GlobalConfig, Packages, IsExact) -> - RepoPlugins = proplists:get_value(repo_plugins, GlobalConfig, ?DEFAULT_API_MODULES), - write_not_installed_package_info1(Packages, RepoPlugins, IsExact). +print_not_installed_package_info(_State=#epm_state{}, Packages, IsExact) -> + RepoPlugins = epm_cfg:get(repo_plugins, ?DEFAULT_API_MODULES), + print_not_installed_internal(Packages, RepoPlugins, IsExact). -write_not_installed_package_info1(Packages, RepoPlugins, IsExact) -> +print_not_installed_internal(Packages, RepoPlugins, IsExact) -> case fetch_not_installed_package_info(Packages, RepoPlugins, [], IsExact) of [] -> io:format("- not found~n"); @@ -239,24 +242,27 @@ write_not_installed_package_info1(Packages, RepoPlugins, IsExact) -> io:format("===============================~n"), lists:foldl( fun(Repo, Count) -> - Tags = apply(Repo#repository.api_module, tags, [Repo#repository.owner, Repo#repository.name]), - Branches = apply(Repo#repository.api_module, branches, [Repo#repository.owner, Repo#repository.name]), + Tags = apply(Repo#epm_repo.api_module, tags + , [Repo#epm_repo.owner, Repo#epm_repo.name]), + Branches = apply(Repo#epm_repo.api_module, branches + , [Repo#epm_repo.owner, Repo#epm_repo.name]), case Count of 0 -> ok; _ -> io:format("~n") end, - [io:format(" ~s: ~s~n", [Field, if Value == undefined -> ""; true -> - Value end ]) || {Field, Value} <- [ - {"name", Repo#repository.name} , - {"owner", Repo#repository.owner} , - {"followers", Repo#repository.followers} , - {"pushed", Repo#repository.pushed} , - {"homepage", Repo#repository.homepage} , - {"description", Repo#repository.description} , - {"repo plugin", atom_to_list(Repo#repository.api_module)} + [io:format(" ~s: ~s~n" + , [Field + , if Value == undefined -> ""; true -> Value end + ]) || {Field, Value} <- [ + {"name", Repo#epm_repo.name} , + {"owner", Repo#epm_repo.owner} , + {"followers", Repo#epm_repo.followers} , + {"pushed", Repo#epm_repo.pushed} , + {"homepage", Repo#epm_repo.homepage} , + {"description", Repo#epm_repo.description} , + {"repo plugin", atom_to_list(Repo#epm_repo.api_module)} ]], - if - Tags =/= [] -> + if Tags =/= [] -> io:format(" tags:~n"), [io:format(" ~s~n", [Tag]) || Tag <- Tags]; true -> ok @@ -272,7 +278,7 @@ write_not_installed_package_info1(Packages, RepoPlugins, IsExact) -> end. fetch_not_installed_package_info([], _, Acc, _) -> Acc; -fetch_not_installed_package_info([#package{user=User,name=ProjectName}|Tail] +fetch_not_installed_package_info([#epm_package{user=User,name=ProjectName}|Tail] , RepoPlugins, Acc, IsExact) -> Repos = epm_ops:retrieve_remote_repos( RepoPlugins, User, ProjectName, IsExact), @@ -283,70 +289,75 @@ fetch_not_installed_package_info([#package{user=User,name=ProjectName}|Tail] %% ----------------------------------------------------------------------------- %% REMOVE %% ----------------------------------------------------------------------------- -remove_package(_GlobalConfig, #package{ user = User - , name = Name - , vsn = Vsn - , install_dir = InstallDir}) -> +-spec remove_package(#epm_state{}, #epm_package{}) -> #epm_state{}. +remove_package(State=#epm_state{}, #epm_package{ user = User + , name = Name + , vsn = Vsn + , install_dir = InstallDir}) -> io:format("+ removing package ~s-~s-~s from ~s~n" , [User, Name, Vsn, InstallDir]), RemoveCmd = "rm -rf " ++ InstallDir, epm_util:print_cmd_output("~s~n", [RemoveCmd]), epm_util:do_cmd(RemoveCmd, fail), - epm_index:delete_local({User, Name, Vsn}). + epm_index:delete_local({User, Name, Vsn}), + State. %% ----------------------------------------------------------------------------- %% UPDATE %% ----------------------------------------------------------------------------- -update_package(GlobalConfig, Package) -> - Repo = Package#package.repo, - Vsn = Package#package.vsn, +-spec update_package(#epm_state{}, #epm_package{}) -> #epm_state{}. +update_package(State=#epm_state{}, Package=#epm_package{}) -> + Repo = Package#epm_package.repo, + Vsn = Package#epm_package.vsn, %% switch to build home dir - epm_util:set_cwd_build_home(GlobalConfig), + epm_util:set_cwd_build_home(State), %% download correct version of package - LocalProjectDir = apply(Repo#repository.api_module, download_package + LocalProjectDir = apply(Repo#epm_repo.api_module, download_package , [Repo, Vsn]), %% switch to project dir - epm_util:set_cwd_build_home(GlobalConfig), + epm_util:set_cwd_build_home(State), epm_util:set_cwd(LocalProjectDir), %% build/install project %_InstallDir = build_project(GlobalConfig, Package), %% switch to build home dir and delete cloned project - epm_util:set_cwd_build_home(GlobalConfig), - epm_util:del_dir(LocalProjectDir). + epm_util:set_cwd_build_home(State), + epm_util:del_dir(LocalProjectDir), + State. %% ----------------------------------------------------------------------------- %% INSTALL %% ----------------------------------------------------------------------------- -install_package(GlobalConfig, Package) -> - Repo = Package#package.repo, - User = Repo#repository.owner, - Name = Repo#repository.name, - Vsn = Package#package.vsn, +-spec install_package(#epm_state{}, #epm_package{}) -> #epm_state{}. +install_package(State=#epm_state{}, Package=#epm_package{}) -> + Repo = Package#epm_package.repo, + User = Repo#epm_repo.owner, + Name = Repo#epm_repo.name, + Vsn = Package#epm_package.vsn, %% switch to build home dir - epm_util:set_cwd_build_home(GlobalConfig), + epm_util:set_cwd_build_home(State), %% download correct version of package - LocalProjectDir = apply(Repo#repository.api_module, download_package, [Repo, Vsn]), + LocalProjectDir = apply(Repo#epm_repo.api_module, download_package, [Repo, Vsn]), %% switch to project dir - epm_util:set_cwd_build_home(GlobalConfig), + epm_util:set_cwd_build_home(State), epm_util:set_cwd(LocalProjectDir), %% build/install project - InstallDir = "not-building-anything", %build_project(GlobalConfig, Package), + InstallDir = "not-building-anything", %build_project(State, Package), %% switch to build home dir and delete cloned project - epm_util:set_cwd_build_home(GlobalConfig), + epm_util:set_cwd_build_home(State), epm_util:del_dir(LocalProjectDir), - Package1 = Package#package{install_dir = InstallDir}, + Package1 = Package#epm_package{install_dir = InstallDir}, epm_index:insert_local({User, Name, Vsn}, Package1), - ok. + State. install(ProjectName, Config, undefined) -> install(ProjectName, Config, code:lib_dir()); diff --git a/src/epm_package.erl b/src/epm_package.erl index 050b569..88346e1 100644 --- a/src/epm_package.erl +++ b/src/epm_package.erl @@ -4,7 +4,7 @@ -include("epm.hrl"). download_tarball(Repo, Url) -> - LocalProjectDir = Repo#repository.owner ++ "-" ++ Repo#repository.name, + LocalProjectDir = Repo#epm_repo.owner ++ "-" ++ Repo#epm_repo.name, io:format("+ downloading ~s~n", [Url]), case epm_util:http_request(Url, undefined, [{response_format, binary}]) of {ok, "200", _, Bin} -> @@ -18,16 +18,16 @@ download_tarball(Repo, Url) -> epm_util:rn_dir(TarName, LocalProjectDir), LocalProjectDir; {error, Reason} -> - ?EXIT("failed to extract ~s tarball: ~p", [Repo#repository.name, Reason]) + ?EXIT("failed to extract ~s tarball: ~p", [Repo#epm_repo.name, Reason]) end; {error, Reason1} -> - ?EXIT("failed to extract ~s tarball: ~p", [Repo#repository.name, Reason1]) + ?EXIT("failed to extract ~s tarball: ~p", [Repo#epm_repo.name, Reason1]) end; {ok, "404", _, _} -> ?EXIT("remote project does not exist: ~s", [Url]); Error -> io:format("~p~n", [Error]), - ?EXIT("failed to download ~s tarball: ~s", [Repo#repository.name, Url]) + ?EXIT("failed to download ~s tarball: ~s", [Repo#epm_repo.name, Url]) end. tarname([]) -> diff --git a/src/epm_util.erl b/src/epm_util.erl index b27b166..f8453e8 100644 --- a/src/epm_util.erl +++ b/src/epm_util.erl @@ -3,10 +3,10 @@ -include("epm.hrl"). home_dir() -> - case init:get_argument(home) of - {ok, [[H]]} -> [H]; - _ -> [] - end. + case init:get_argument(home) of + {ok, [[H]]} -> [H]; + _ -> [] + end. set_http_proxy(Host, Port) when Host =:= none orelse Port =:= none -> ignored; @@ -36,7 +36,7 @@ request_as_str(Url, Host) -> end. http_request(Url, Host) -> - http_request(Url, Host, []). + http_request(Url, Host, []). http_request(Url, Host, ClientOpts) -> Hdrs = make_headers(Host), @@ -54,7 +54,7 @@ http_request(Url, Host, ClientOpts) -> end. http_options(ClientOpts) -> - proxy_options() ++ ClientOpts. + proxy_options() ++ ClientOpts. proxy_options() -> case epm_cfg:get(proxy_host) of @@ -94,10 +94,8 @@ eval(Str) -> {ok, Tokens, _} -> case erl_parse:parse_exprs(Tokens) of {ok, Forms} -> - case erl_eval:exprs(Forms, []) of - {value, Terms, _} -> Terms; - _ -> error - end; + {value, Terms, _} = erl_eval:exprs(Forms, []), + Terms; _ -> error end; _ -> error @@ -185,8 +183,8 @@ print_cmd_output(Format, Args, true) -> Output = re:replace(Output0, "\~", "", [global, {return, list}]), io:format(string:substr(Output, 1, length(Output)-4), []). -set_cwd_build_home(GlobalConfig) -> - set_cwd(proplists:get_value(build_dir, GlobalConfig, ".")). +set_cwd_build_home(_State=#epm_state{}) -> + set_cwd(epm_cfg:get(build_dir, ".")). set_cwd(Dir) -> case file:set_cwd(Dir) of