headed/headless dev scripts, runlocal works again
This commit is contained in:
parent
9441c7a879
commit
7062ffe747
@ -19,7 +19,7 @@
|
|||||||
-license("GPL-3.0").
|
-license("GPL-3.0").
|
||||||
|
|
||||||
|
|
||||||
-export([run/0, run/1]).
|
-export([do/0, do/1]).
|
||||||
-export([subscribe/1, unsubscribe/0]).
|
-export([subscribe/1, unsubscribe/0]).
|
||||||
-export([start/2, stop/1, stop/0]).
|
-export([start/2, stop/1, stop/0]).
|
||||||
-export([usage_exit/1]).
|
-export([usage_exit/1]).
|
||||||
@ -69,71 +69,68 @@
|
|||||||
|
|
||||||
%%% Command Dispatch
|
%%% Command Dispatch
|
||||||
|
|
||||||
-spec run() -> no_return().
|
-spec do() -> no_return().
|
||||||
|
|
||||||
run() ->
|
do() ->
|
||||||
run([]).
|
do([]).
|
||||||
|
|
||||||
|
|
||||||
-spec run(Args) -> no_return()
|
-spec do(Args) -> no_return()
|
||||||
when Args :: [string()].
|
when Args :: [string()].
|
||||||
%% Dispatch work functions based on the nature of the input arguments.
|
%% Dispatch work functions based on the nature of the input arguments.
|
||||||
|
|
||||||
run(["help"]) ->
|
do(["help"]) ->
|
||||||
usage_exit(0);
|
usage_exit(0);
|
||||||
run(["run", PackageString | Args]) ->
|
do(["run", PackageString | Args]) ->
|
||||||
ok = start(),
|
ok = start(),
|
||||||
run(PackageString, Args);
|
run(PackageString, Args);
|
||||||
run(["runlocal" | ArgV]) ->
|
do(["runlocal" | ArgV]) ->
|
||||||
ok = start(),
|
ok = start(),
|
||||||
run_local(ArgV);
|
run_local(ArgV);
|
||||||
run(["init", "app", PackageString]) ->
|
do(["init", "app", PackageString]) ->
|
||||||
ok = compatibility_check([unix]),
|
ok = compatibility_check([unix]),
|
||||||
ok = zx_local:initialize(app, PackageString),
|
ok = zx_local:initialize(app, PackageString),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["init", "lib", PackageString]) ->
|
do(["init", "lib", PackageString]) ->
|
||||||
ok = compatibility_check([unix]),
|
ok = compatibility_check([unix]),
|
||||||
ok = zx_local:initialize(lib, PackageString),
|
ok = zx_local:initialize(lib, PackageString),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["install", PackageFile]) ->
|
do(["install", PackageFile]) ->
|
||||||
ok = zx_local:assimilate(PackageFile),
|
ok = zx_local:assimilate(PackageFile),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["set", "dep", PackageString]) ->
|
do(["set", "dep", PackageString]) ->
|
||||||
ok = zx_local:set_dep(PackageString),
|
ok = zx_local:set_dep(PackageString),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["set", "version", VersionString]) ->
|
do(["set", "version", VersionString]) ->
|
||||||
ok = compatibility_check([unix]),
|
ok = compatibility_check([unix]),
|
||||||
ok = zx_local:set_version(VersionString),
|
ok = zx_local:set_version(VersionString),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["verup", Level]) ->
|
do(["verup", Level]) ->
|
||||||
ok = compatibility_check([unix]),
|
ok = compatibility_check([unix]),
|
||||||
ok = zx_local:verup(Level),
|
ok = zx_local:verup(Level),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["list", "realms"]) ->
|
do(["list", "realms"]) ->
|
||||||
ok = zx_local:list_realms(),
|
ok = zx_local:list_realms(),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["list", "packages", Realm]) ->
|
do(["list", "packages", Realm]) ->
|
||||||
ok = start(),
|
ok = start(),
|
||||||
ok = zx_local:list_packages(Realm),
|
ok = zx_local:list_packages(Realm),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["list", "versions", PackageName]) ->
|
do(["list", "versions", PackageName]) ->
|
||||||
ok = start(),
|
ok = start(),
|
||||||
ok = zx_local:list_versions(PackageName),
|
ok = zx_local:list_versions(PackageName),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["add", "realm", RealmFile]) ->
|
do(["add", "realm", RealmFile]) ->
|
||||||
ok = zx_local:add_realm(RealmFile),
|
ok = zx_local:add_realm(RealmFile),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["drop", "dep", PackageString]) ->
|
do(["drop", "dep", PackageString]) ->
|
||||||
PackageID = zx_lib:package_id(PackageString),
|
PackageID = zx_lib:package_id(PackageString),
|
||||||
ok = zx_local:drop_dep(PackageID),
|
ok = zx_local:drop_dep(PackageID),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["drop", "realm", Realm]) ->
|
do(["package"]) ->
|
||||||
ok = zx_local:drop_realm(Realm),
|
|
||||||
halt(0);
|
|
||||||
run(["package"]) ->
|
|
||||||
{ok, TargetDir} = file:get_cwd(),
|
{ok, TargetDir} = file:get_cwd(),
|
||||||
zx_local:package(TargetDir);
|
zx_local:package(TargetDir);
|
||||||
run(["package", TargetDir]) ->
|
do(["package", TargetDir]) ->
|
||||||
case filelib:is_dir(TargetDir) of
|
case filelib:is_dir(TargetDir) of
|
||||||
true ->
|
true ->
|
||||||
ok = zx_local:package(TargetDir),
|
ok = zx_local:package(TargetDir),
|
||||||
@ -142,49 +139,61 @@ run(["package", TargetDir]) ->
|
|||||||
ok = log(error, "Target directory ~tp does not exist!", [TargetDir]),
|
ok = log(error, "Target directory ~tp does not exist!", [TargetDir]),
|
||||||
halt(22)
|
halt(22)
|
||||||
end;
|
end;
|
||||||
run(["dialyze"]) ->
|
do(["dialyze"]) ->
|
||||||
ok = zx_local:dialyze(),
|
ok = zx_local:dialyze(),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["create", "user", Realm, Name]) ->
|
do(["create", "user", Realm, Name]) ->
|
||||||
ok = zx_local:create_user(Realm, Name),
|
ok = zx_local:create_user(Realm, Name),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["create", "keypair"]) ->
|
do(["create", "keypair"]) ->
|
||||||
ok = zx_local:grow_a_pair(),
|
ok = zx_local:grow_a_pair(),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["drop", "key", Realm, KeyName]) ->
|
do(["drop", "key", Realm, KeyName]) ->
|
||||||
ok = zx_local:drop_key({Realm, KeyName}),
|
ok = zx_local:drop_key({Realm, KeyName}),
|
||||||
halt(0);
|
halt(0);
|
||||||
run(["create", "plt"]) ->
|
do(["create", "plt"]) ->
|
||||||
zx_local:create_plt();
|
ok = zx_local:create_plt(),
|
||||||
run(["create", "realm"]) ->
|
halt(0);
|
||||||
zx_local:create_realm();
|
do(["create", "realm"]) ->
|
||||||
run(["create", "realmfile", Realm]) ->
|
ok = zx_local:create_realm(),
|
||||||
zx_local:create_realmfile(Realm);
|
halt(0);
|
||||||
run(["list", "pending", PackageName]) ->
|
do(["create", "realmfile", Realm]) ->
|
||||||
|
ok = zx_local:create_realmfile(Realm, "."),
|
||||||
|
halt(0);
|
||||||
|
do(["takeover", Realm]) ->
|
||||||
|
ok = zx_local:takeover(Realm),
|
||||||
|
halt(0);
|
||||||
|
do(["abdicate", Realm]) ->
|
||||||
|
ok = zx_local:abdicate(Realm),
|
||||||
|
halt(0);
|
||||||
|
do(["drop", "realm", Realm]) ->
|
||||||
|
ok = zx_local:drop_realm(Realm),
|
||||||
|
halt(0);
|
||||||
|
do(["list", "pending", PackageName]) ->
|
||||||
zx_auth:list_pending(PackageName);
|
zx_auth:list_pending(PackageName);
|
||||||
run(["list", "resigns", Realm]) ->
|
do(["list", "resigns", Realm]) ->
|
||||||
zx_auth:list_resigns(Realm);
|
zx_auth:list_resigns(Realm);
|
||||||
run(["submit", PackageFile]) ->
|
do(["submit", PackageFile]) ->
|
||||||
zx_auth:submit(PackageFile);
|
zx_auth:submit(PackageFile);
|
||||||
run(["review", PackageString]) ->
|
do(["review", PackageString]) ->
|
||||||
zx_auth:review(PackageString);
|
zx_auth:review(PackageString);
|
||||||
run(["approve", PackageString]) ->
|
do(["approve", PackageString]) ->
|
||||||
PackageID = zx_lib:package_id(PackageString),
|
PackageID = zx_lib:package_id(PackageString),
|
||||||
zx_auth:approve(PackageID);
|
zx_auth:approve(PackageID);
|
||||||
run(["reject", PackageString]) ->
|
do(["reject", PackageString]) ->
|
||||||
PackageID = zx_lib:package_id(PackageString),
|
PackageID = zx_lib:package_id(PackageString),
|
||||||
zx_auth:reject(PackageID);
|
zx_auth:reject(PackageID);
|
||||||
run(["accept", PackageString]) ->
|
do(["accept", PackageString]) ->
|
||||||
zx_auth:accept(PackageString);
|
zx_auth:accept(PackageString);
|
||||||
run(["add", "packager", Package, UserName]) ->
|
do(["add", "packager", Package, UserName]) ->
|
||||||
zx_auth:add_packager(Package, UserName);
|
zx_auth:add_packager(Package, UserName);
|
||||||
run(["add", "maintainer", Package, UserName]) ->
|
do(["add", "maintainer", Package, UserName]) ->
|
||||||
zx_auth:add_maintainer(Package, UserName);
|
zx_auth:add_maintainer(Package, UserName);
|
||||||
run(["add", "sysop", Package, UserName]) ->
|
do(["add", "sysop", Package, UserName]) ->
|
||||||
zx_auth:add_sysop(Package, UserName);
|
zx_auth:add_sysop(Package, UserName);
|
||||||
run(["add", "package", PackageName]) ->
|
do(["add", "package", PackageName]) ->
|
||||||
zx_auth:add_package(PackageName);
|
zx_auth:add_package(PackageName);
|
||||||
run(_) ->
|
do(_) ->
|
||||||
usage_exit(22).
|
usage_exit(22).
|
||||||
|
|
||||||
|
|
||||||
@ -317,7 +326,6 @@ unsubscribe() ->
|
|||||||
|
|
||||||
run(Identifier, RunArgs) ->
|
run(Identifier, RunArgs) ->
|
||||||
ok = file:set_cwd(zx_lib:zomp_dir()),
|
ok = file:set_cwd(zx_lib:zomp_dir()),
|
||||||
ok = start(),
|
|
||||||
FuzzyID =
|
FuzzyID =
|
||||||
case zx_lib:package_id(Identifier) of
|
case zx_lib:package_id(Identifier) of
|
||||||
{ok, Fuzzy} ->
|
{ok, Fuzzy} ->
|
||||||
@ -329,12 +337,9 @@ run(Identifier, RunArgs) ->
|
|||||||
ok = build(PackageID),
|
ok = build(PackageID),
|
||||||
Dir = zx_lib:package_dir(PackageID),
|
Dir = zx_lib:package_dir(PackageID),
|
||||||
{ok, Meta} = zx_lib:read_project_meta(Dir),
|
{ok, Meta} = zx_lib:read_project_meta(Dir),
|
||||||
execute(PackageID, Meta, Dir, RunArgs).
|
prepare(PackageID, Meta, Dir, RunArgs).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Execution of local project
|
|
||||||
|
|
||||||
-spec run_local(RunArgs) -> no_return()
|
-spec run_local(RunArgs) -> no_return()
|
||||||
when RunArgs :: [term()].
|
when RunArgs :: [term()].
|
||||||
%% @private
|
%% @private
|
||||||
@ -352,11 +357,10 @@ run_local(RunArgs) ->
|
|||||||
ok = zx_lib:build(),
|
ok = zx_lib:build(),
|
||||||
{ok, Dir} = file:get_cwd(),
|
{ok, Dir} = file:get_cwd(),
|
||||||
ok = file:set_cwd(zx_lib:zomp_dir()),
|
ok = file:set_cwd(zx_lib:zomp_dir()),
|
||||||
ok = start(),
|
prepare(PackageID, Meta, Dir, RunArgs).
|
||||||
execute(PackageID, Meta, Dir, RunArgs).
|
|
||||||
|
|
||||||
|
|
||||||
-spec execute(PackageID, Meta, Dir, RunArgs) -> no_return()
|
-spec prepare(PackageID, Meta, Dir, RunArgs) -> no_return()
|
||||||
when PackageID :: package_id(),
|
when PackageID :: package_id(),
|
||||||
Meta :: package_meta(),
|
Meta :: package_meta(),
|
||||||
Dir :: file:filename(),
|
Dir :: file:filename(),
|
||||||
@ -364,21 +368,43 @@ run_local(RunArgs) ->
|
|||||||
%% @private
|
%% @private
|
||||||
%% Execution prep common to all packages.
|
%% Execution prep common to all packages.
|
||||||
|
|
||||||
execute(PackageID, Meta, Dir, RunArgs) ->
|
prepare(PackageID, Meta, Dir, RunArgs) ->
|
||||||
PackageString = zx_lib:package_string(PackageID),
|
{ok, PackageString} = zx_lib:package_string(PackageID),
|
||||||
ok = log(info, "Preparing ~ts...", [PackageString]),
|
ok = log(info, "Preparing ~ts...", [PackageString]),
|
||||||
Type = maps:get(type, Meta),
|
Type = maps:get(type, Meta),
|
||||||
Deps = maps:get(deps, Meta),
|
Deps = maps:get(deps, Meta),
|
||||||
case zx_daemon:fetch(Deps) of
|
NotInstalled = fun(P) -> not filelib:is_dir(zx_lib:ppath(lib, P)) end,
|
||||||
{{ok, _}, {error, []}} ->
|
Needed = lists:filter(NotInstalled, Deps),
|
||||||
ok = lists:foreach(fun install/1, Deps),
|
Pending = lists:map(fun zx_daemon:fetch/1, Needed),
|
||||||
ok = lists:foreach(fun build/1, Deps),
|
case await_fetches(Pending) of
|
||||||
execute(Type, PackageID, Dir, Meta, RunArgs);
|
ok ->
|
||||||
{{ok, _}, {error, Errors}} ->
|
ok = lists:foreach(fun install/1, Needed),
|
||||||
|
ok = lists:foreach(fun build/1, Needed),
|
||||||
|
execute(Type, PackageID, Meta, Dir, RunArgs);
|
||||||
|
{error, Errors} ->
|
||||||
error_exit("Failed package fetches: ~tp", [Errors], ?LINE)
|
error_exit("Failed package fetches: ~tp", [Errors], ?LINE)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
await_fetches([]) -> ok;
|
||||||
|
await_fetches(Pending) -> await_fetches(Pending, []).
|
||||||
|
|
||||||
|
|
||||||
|
await_fetches([], []) ->
|
||||||
|
ok;
|
||||||
|
await_fetches([], Errors) ->
|
||||||
|
{error, Errors};
|
||||||
|
await_fetches(Pending, Errors) ->
|
||||||
|
{NewPending, NewErrors} =
|
||||||
|
receive
|
||||||
|
{z_reply, ID, ok} ->
|
||||||
|
{lists:delete(ID, Pending), Errors};
|
||||||
|
{z_reply, ID, {error, Package, Reason}} ->
|
||||||
|
{lists:delete(ID, Pending), [{Package, Reason} | Errors]}
|
||||||
|
end,
|
||||||
|
await_fetches(NewPending, NewErrors).
|
||||||
|
|
||||||
|
|
||||||
-spec execute(Type, PackageID, Meta, Dir, RunArgs) -> no_return()
|
-spec execute(Type, PackageID, Meta, Dir, RunArgs) -> no_return()
|
||||||
when Type :: app | lib,
|
when Type :: app | lib,
|
||||||
PackageID :: package_id(),
|
PackageID :: package_id(),
|
||||||
@ -390,12 +416,13 @@ execute(PackageID, Meta, Dir, RunArgs) ->
|
|||||||
%% the exec_wait/1 loop to wait for any queries from the application.
|
%% the exec_wait/1 loop to wait for any queries from the application.
|
||||||
|
|
||||||
execute(app, PackageID, Meta, Dir, RunArgs) ->
|
execute(app, PackageID, Meta, Dir, RunArgs) ->
|
||||||
PackageString = zx_lib:package_string(PackageID),
|
{ok, PackageString} = zx_lib:package_string(PackageID),
|
||||||
ok = log(info, "Starting ~ts.", [PackageString]),
|
ok = log(info, "Starting ~ts.", [PackageString]),
|
||||||
Name = element(2, PackageID),
|
Name = element(2, PackageID),
|
||||||
AppMod = list_to_atom(Name),
|
AppTag = list_to_atom(Name),
|
||||||
ok = zx_daemon:pass_meta(Meta, Dir),
|
{AppMod, _} = maps:get(appmod, Meta),
|
||||||
ok = ensure_all_started(AppMod),
|
ok = zx_daemon:pass_meta(Meta, Dir, RunArgs),
|
||||||
|
ok = ensure_all_started(AppTag),
|
||||||
ok = pass_argv(AppMod, RunArgs),
|
ok = pass_argv(AppMod, RunArgs),
|
||||||
log(info, "Launcher complete.");
|
log(info, "Launcher complete.");
|
||||||
execute(lib, PackageID, _, _, _) ->
|
execute(lib, PackageID, _, _, _) ->
|
||||||
|
|||||||
@ -127,14 +127,14 @@ timeout(#d{timeout = Timeout}) ->
|
|||||||
Timeout.
|
Timeout.
|
||||||
|
|
||||||
|
|
||||||
-spec timeout(Data, Value) -> NewData
|
-spec timeout(Value, Data) -> NewData
|
||||||
when Data :: data(),
|
when Value :: pos_integer(),
|
||||||
Value :: pos_integer(),
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Set the timeout attribute to a new value.
|
%% Set the timeout attribute to a new value.
|
||||||
|
|
||||||
timeout(Data, Value)
|
timeout(Value, Data)
|
||||||
when is_integer(Value) and Value > 0 ->
|
when is_integer(Value) and Value > 0 ->
|
||||||
Data#d{timeout = Value}.
|
Data#d{timeout = Value}.
|
||||||
|
|
||||||
@ -147,14 +147,14 @@ retries(#d{retries = {_, Retries}}) ->
|
|||||||
Retries.
|
Retries.
|
||||||
|
|
||||||
|
|
||||||
-spec retries(Data, Value) -> NewData
|
-spec retries(Value, Data) -> NewData
|
||||||
when Data :: data(),
|
when Value :: non_neg_integer(),
|
||||||
Value :: non_neg_integer(),
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Set the retries attribute to a new value.
|
%% Set the retries attribute to a new value.
|
||||||
|
|
||||||
retries(Data = #d{retries = {Remaining, _}}, Value)
|
retries(Value, Data = #d{retries = {Remaining, _}})
|
||||||
when is_integer(Value) and Value >= 0 ->
|
when is_integer(Value) and Value >= 0 ->
|
||||||
Data#d{retries = {Remaining, Value}}.
|
Data#d{retries = {Remaining, Value}}.
|
||||||
|
|
||||||
@ -192,14 +192,14 @@ maxconn(#d{maxconn = MaxConn}) ->
|
|||||||
MaxConn.
|
MaxConn.
|
||||||
|
|
||||||
|
|
||||||
-spec maxconn(Data, Value) -> NewData
|
-spec maxconn(Value, Data) -> NewData
|
||||||
when Data :: data(),
|
when Value :: pos_integer(),
|
||||||
Value :: pos_integer(),
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Set the value of maxconn.
|
%% Set the value of maxconn.
|
||||||
|
|
||||||
maxconn(Data, Value)
|
maxconn(Value, Data)
|
||||||
when is_integer(Value) and Value > 0 ->
|
when is_integer(Value) and Value > 0 ->
|
||||||
Data#d{maxconn = Value}.
|
Data#d{maxconn = Value}.
|
||||||
|
|
||||||
@ -212,24 +212,24 @@ managed(#d{managed = Managed}) ->
|
|||||||
sets:to_list(Managed).
|
sets:to_list(Managed).
|
||||||
|
|
||||||
|
|
||||||
-spec managed(Data, List) -> NewData
|
-spec managed(List, Data) -> NewData
|
||||||
when Data :: data(),
|
when List :: [zx:realm()],
|
||||||
List :: [zx:realm()],
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Reset the set of managed realms entirely.
|
%% Reset the set of managed realms entirely.
|
||||||
%% The realms must be configured on the current realm at a minimum.
|
%% The realms must be configured on the current realm at a minimum.
|
||||||
|
|
||||||
managed(Data, List) ->
|
managed(List, Data) ->
|
||||||
Desired = sets:from_list(List),
|
Desired = sets:from_list(List),
|
||||||
Configured = sets:from_list(zx_lib:list_realms()),
|
Configured = sets:from_list(zx_lib:list_realms()),
|
||||||
NewManaged = sets:intersection(Desired, Configured),
|
NewManaged = sets:intersection(Desired, Configured),
|
||||||
Data#d{managed = NewManaged}.
|
Data#d{managed = NewManaged}.
|
||||||
|
|
||||||
|
|
||||||
-spec add_managed(Data, Realm) -> Result
|
-spec add_managed(Realm, Data) -> Result
|
||||||
when Data :: data(),
|
when Realm :: zx:realm(),
|
||||||
Realm :: zx:realm(),
|
Data :: data(),
|
||||||
Result :: {ok, NewData}
|
Result :: {ok, NewData}
|
||||||
| {error, unconfigured},
|
| {error, unconfigured},
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
@ -238,8 +238,8 @@ managed(Data, List) ->
|
|||||||
%% the current node. This node will then behave as the prime node for the realm (whether
|
%% the current node. This node will then behave as the prime node for the realm (whether
|
||||||
%% it is or not).
|
%% it is or not).
|
||||||
|
|
||||||
add_managed(Data = #d{managed = Managed}, Realm) ->
|
add_managed(Realm, Data = #d{managed = Managed}) ->
|
||||||
case lists:member(Realm, zx_lib:list_realms()) of
|
case zx_lib:realm_exists(Realm) of
|
||||||
true ->
|
true ->
|
||||||
NewData = Data#d{managed = sets:add_element(Realm, Managed)},
|
NewData = Data#d{managed = sets:add_element(Realm, Managed)},
|
||||||
ok = log(info, "Now managing realm: ~tp", [Realm]),
|
ok = log(info, "Now managing realm: ~tp", [Realm]),
|
||||||
@ -250,16 +250,16 @@ add_managed(Data = #d{managed = Managed}, Realm) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec rem_managed(Data, Realm) -> Result
|
-spec rem_managed(Realm, Data) -> Result
|
||||||
when Data :: data(),
|
when Realm :: zx:realm(),
|
||||||
Realm :: zx:realm(),
|
Data :: data(),
|
||||||
Result :: {ok, NewData}
|
Result :: {ok, NewData}
|
||||||
| {error, unmanaged},
|
| {error, unmanaged},
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Stop managing a realm.
|
%% Stop managing a realm.
|
||||||
|
|
||||||
rem_managed(Data = #d{managed = Managed}, Realm) ->
|
rem_managed(Realm, Data = #d{managed = Managed}) ->
|
||||||
case sets:is_element(Realm, Managed) of
|
case sets:is_element(Realm, Managed) of
|
||||||
true ->
|
true ->
|
||||||
NewData = Data#d{managed = sets:del_element(Realm, Managed)},
|
NewData = Data#d{managed = sets:del_element(Realm, Managed)},
|
||||||
@ -279,20 +279,20 @@ mirrors(#d{mirrors = Mirrors}) ->
|
|||||||
Mirrors.
|
Mirrors.
|
||||||
|
|
||||||
|
|
||||||
-spec mirrors(Data, Hosts) -> NewData
|
-spec mirrors(Hosts, Data) -> NewData
|
||||||
when Data :: data(),
|
when Hosts :: [zx:host()],
|
||||||
Hosts :: [zx:host()],
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @private
|
%% @private
|
||||||
%% Reset the mirror configuration.
|
%% Reset the mirror configuration.
|
||||||
|
|
||||||
mirrors(Data, Hosts) ->
|
mirrors(Hosts, Data) ->
|
||||||
Data#d{mirrors = Hosts}.
|
Data#d{mirrors = Hosts}.
|
||||||
|
|
||||||
|
|
||||||
-spec add_mirror(Data, Host) -> NewData
|
-spec add_mirror(Host, Data) -> NewData
|
||||||
when Data :: data(),
|
when Host :: zx:host(),
|
||||||
Host :: zx:host(),
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Add a mirror to the permanent configuration.
|
%% Add a mirror to the permanent configuration.
|
||||||
@ -304,14 +304,14 @@ add_mirror(Data = #d{mirrors = Mirrors}, Host) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec rem_mirror(Data, Host) -> NewData
|
-spec rem_mirror(Host, Data) -> NewData
|
||||||
when Data :: data(),
|
when Host :: zx:host(),
|
||||||
Host :: zx:host(),
|
Data :: data(),
|
||||||
NewData :: data().
|
NewData :: data().
|
||||||
%% @private
|
%% @private
|
||||||
%% Remove a host from the list of permanent mirrors.
|
%% Remove a host from the list of permanent mirrors.
|
||||||
|
|
||||||
rem_mirror(Data = #d{mirrors = Mirrors}, Host) ->
|
rem_mirror(Host, Data = #d{mirrors = Mirrors}) ->
|
||||||
Data#d{mirrors = lists:delete(Host, Mirrors)}.
|
Data#d{mirrors = lists:delete(Host, Mirrors)}.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -147,7 +147,7 @@
|
|||||||
-export([pass_meta/3,
|
-export([pass_meta/3,
|
||||||
subscribe/1, unsubscribe/1,
|
subscribe/1, unsubscribe/1,
|
||||||
list/0, list/1, list/2, list/3, latest/1,
|
list/0, list/1, list/2, list/3, latest/1,
|
||||||
fetch_zsp/1, fetch_key/1,
|
fetch/1, verify_key/1,
|
||||||
pending/1, packagers/1, maintainers/1, sysops/1]).
|
pending/1, packagers/1, maintainers/1, sysops/1]).
|
||||||
-export([report/1, result/2, notify/2]).
|
-export([report/1, result/2, notify/2]).
|
||||||
-export([start_link/0, stop/0]).
|
-export([start_link/0, stop/0]).
|
||||||
@ -326,6 +326,9 @@
|
|||||||
%% references.
|
%% references.
|
||||||
|
|
||||||
pass_meta(Meta, Dir, ArgV) ->
|
pass_meta(Meta, Dir, ArgV) ->
|
||||||
|
ok = log(info, "Meta: ~tp", [Meta]),
|
||||||
|
ok = log(info, "Dir : ~tp", [Dir]),
|
||||||
|
ok = log(info, "ArgV: ~tp", [ArgV]),
|
||||||
gen_server:cast(?MODULE, {pass_meta, Meta, Dir, ArgV}).
|
gen_server:cast(?MODULE, {pass_meta, Meta, Dir, ArgV}).
|
||||||
|
|
||||||
|
|
||||||
@ -446,7 +449,7 @@ latest({Realm, Name, Version}) ->
|
|||||||
request({latest, Realm, Name, Version}).
|
request({latest, Realm, Name, Version}).
|
||||||
|
|
||||||
|
|
||||||
-spec fetch_zsp(PackageID) -> {ok, RequestID}
|
-spec fetch(PackageID) -> {ok, RequestID}
|
||||||
when PackageID :: zx:package_id(),
|
when PackageID :: zx:package_id(),
|
||||||
RequestID :: integer().
|
RequestID :: integer().
|
||||||
%% @doc
|
%% @doc
|
||||||
@ -458,27 +461,28 @@ latest({Realm, Name, Version}) ->
|
|||||||
%% Response messages are of the type `result()' where the third element is of the
|
%% Response messages are of the type `result()' where the third element is of the
|
||||||
%% type `fetch_result()'.
|
%% type `fetch_result()'.
|
||||||
|
|
||||||
fetch_zsp(PackageID = {Realm, Name, Version}) ->
|
fetch({Realm, Name, Version}) ->
|
||||||
true = zx_lib:valid_lower0_9(Realm),
|
true = zx_lib:valid_lower0_9(Realm),
|
||||||
true = zx_lib:valid_lower0_9(Name),
|
true = zx_lib:valid_lower0_9(Name),
|
||||||
true = zx_lib:valid_version(Version),
|
true = zx_lib:valid_version(Version),
|
||||||
request({fetch, zsp, PackageID}).
|
request({fetch, Realm, Name, Version}).
|
||||||
|
|
||||||
|
|
||||||
-spec fetch_key(KeyID) -> {ok, RequestID}
|
-spec verify_key(KeyID) -> {ok, RequestID}
|
||||||
when KeyID :: zx:key_id(),
|
when KeyID :: zx:key_id(),
|
||||||
RequestID :: id().
|
RequestID :: id().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Request a public key be fetched from its relevant realm.
|
%% Request a public key be fetched from its upstream, and pursue the key validation
|
||||||
|
%% chain until a key in possession is found or the chain is proven to be broken.
|
||||||
%% Crashes the caller if either component of the KeyID is illegal.
|
%% Crashes the caller if either component of the KeyID is illegal.
|
||||||
%%
|
%%
|
||||||
%% Response messages are of the type `result()' where the third element is of the
|
%% Response messages are of the type `result()' where the third element is of the
|
||||||
%% type `key_result()'.
|
%% type `key_result()'.
|
||||||
|
|
||||||
fetch_key(KeyID = {Realm, KeyName}) ->
|
verify_key({Realm, KeyName}) ->
|
||||||
true = zx_lib:valid_lower0_9(Realm),
|
true = zx_lib:valid_lower0_9(Realm),
|
||||||
true = zx_lib:valid_lower0_9(KeyName),
|
true = zx_lib:valid_lower0_9(KeyName),
|
||||||
request({fetch, key, KeyID}).
|
request({verify_key, Realm, KeyName}).
|
||||||
|
|
||||||
|
|
||||||
-spec pending(Package) -> {ok, RequestID}
|
-spec pending(Package) -> {ok, RequestID}
|
||||||
|
|||||||
@ -105,9 +105,7 @@ prompt_keygen() ->
|
|||||||
-spec generate_rsa(KeyID) -> Result
|
-spec generate_rsa(KeyID) -> Result
|
||||||
when KeyID :: zx:key_id(),
|
when KeyID :: zx:key_id(),
|
||||||
Result :: ok
|
Result :: ok
|
||||||
| {error, keygen_fail},
|
| {error, keygen_fail}.
|
||||||
KeyFile :: file:filename(),
|
|
||||||
PubFile :: file:filename().
|
|
||||||
%% @private
|
%% @private
|
||||||
%% Generate an RSA keypair and write them in der format to the current directory, using
|
%% Generate an RSA keypair and write them in der format to the current directory, using
|
||||||
%% filenames derived from Prefix.
|
%% filenames derived from Prefix.
|
||||||
|
|||||||
@ -15,8 +15,8 @@
|
|||||||
-license("GPL-3.0").
|
-license("GPL-3.0").
|
||||||
|
|
||||||
-export([zomp_dir/0, find_zomp_dir/0,
|
-export([zomp_dir/0, find_zomp_dir/0,
|
||||||
path/1, path/2, path/3,
|
path/1, path/2, path/3, path/4, ppath/2,
|
||||||
force_dir/1,
|
force_dir/1, mktemp_dir/1,
|
||||||
list_realms/0,
|
list_realms/0,
|
||||||
hosts_cache_file/1, get_prime/1, realm_meta/1,
|
hosts_cache_file/1, get_prime/1, realm_meta/1,
|
||||||
read_project_meta/0, read_project_meta/1, read_package_meta/1,
|
read_project_meta/0, read_project_meta/1, read_package_meta/1,
|
||||||
@ -71,13 +71,13 @@ find_zomp_dir() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec path(Type) -> Result
|
-spec path(Type) -> Path
|
||||||
when Type :: etc
|
when Type :: etc
|
||||||
| var
|
| var
|
||||||
| tmp
|
| tmp
|
||||||
| log
|
| log
|
||||||
| lib,
|
| lib,
|
||||||
Result :: file:filename().
|
Path :: file:filename().
|
||||||
%% @private
|
%% @private
|
||||||
%% Return the top-level path of the given type in the Zomp/ZX system.
|
%% Return the top-level path of the given type in the Zomp/ZX system.
|
||||||
|
|
||||||
@ -85,17 +85,19 @@ path(etc) -> filename:join(zomp_dir(), "etc");
|
|||||||
path(var) -> filename:join(zomp_dir(), "var");
|
path(var) -> filename:join(zomp_dir(), "var");
|
||||||
path(tmp) -> filename:join(zomp_dir(), "tmp");
|
path(tmp) -> filename:join(zomp_dir(), "tmp");
|
||||||
path(log) -> filename:join(zomp_dir(), "log");
|
path(log) -> filename:join(zomp_dir(), "log");
|
||||||
|
path(key) -> filename:join(zomp_dir(), "key");
|
||||||
|
path(zsp) -> filename:join(zomp_dir(), "zsp");
|
||||||
path(lib) -> filename:join(zomp_dir(), "lib").
|
path(lib) -> filename:join(zomp_dir(), "lib").
|
||||||
|
|
||||||
|
|
||||||
-spec path(Type, Realm) -> Result
|
-spec path(Type, Realm) -> Path
|
||||||
when Type :: etc
|
when Type :: etc
|
||||||
| var
|
| var
|
||||||
| tmp
|
| tmp
|
||||||
| log
|
| log
|
||||||
| lib,
|
| lib,
|
||||||
Realm :: zx:realm(),
|
Realm :: zx:realm(),
|
||||||
Result :: file:filename().
|
Path :: file:filename().
|
||||||
%% @private
|
%% @private
|
||||||
%% Return the realm-level path of the given type in the Zomp/ZX system.
|
%% Return the realm-level path of the given type in the Zomp/ZX system.
|
||||||
|
|
||||||
@ -103,15 +105,15 @@ path(Type, Realm) ->
|
|||||||
filename:join(path(Type), Realm).
|
filename:join(path(Type), Realm).
|
||||||
|
|
||||||
|
|
||||||
-spec path(Type, Realm, Name) -> Result
|
-spec path(Type, Realm, Name) -> Path
|
||||||
when Type :: etc
|
when Type :: etc
|
||||||
| var
|
| var
|
||||||
| tmp
|
| tmp
|
||||||
| log
|
| log
|
||||||
| lib,
|
| lib,
|
||||||
Realm :: zx:realm(),
|
Realm :: zx:realm(),
|
||||||
Name :: zx:name(),
|
Name :: zx:name(),
|
||||||
Result :: file:filename().
|
Path :: file:filename().
|
||||||
%% @private
|
%% @private
|
||||||
%% Return the package-level path of the given type in the Zomp/ZX system.
|
%% Return the package-level path of the given type in the Zomp/ZX system.
|
||||||
|
|
||||||
@ -119,6 +121,40 @@ path(Type, Realm, Name) ->
|
|||||||
filename:join([path(Type), Realm, Name]).
|
filename:join([path(Type), Realm, Name]).
|
||||||
|
|
||||||
|
|
||||||
|
-spec path(Type, Realm, Name, Version) -> Path
|
||||||
|
when Type :: etc
|
||||||
|
| var
|
||||||
|
| tmp
|
||||||
|
| log
|
||||||
|
| lib,
|
||||||
|
Realm :: zx:realm(),
|
||||||
|
Name :: zx:name(),
|
||||||
|
Version :: zx:version(),
|
||||||
|
Path :: file:filename().
|
||||||
|
%% @private
|
||||||
|
%% Return the version-specific level path of the given type in the Zomp/ZX system.
|
||||||
|
|
||||||
|
path(Type, Realm, Name, Version) ->
|
||||||
|
{ok, VersionString} = version_to_string(Version),
|
||||||
|
filename:join([path(Type), Realm, Name, VersionString]).
|
||||||
|
|
||||||
|
|
||||||
|
-spec ppath(Type, PackageID) -> Path
|
||||||
|
when Type :: etc
|
||||||
|
| var
|
||||||
|
| tmp
|
||||||
|
| log
|
||||||
|
| lib,
|
||||||
|
PackageID :: zx:package_id(),
|
||||||
|
Path :: file:filename().
|
||||||
|
%% @private
|
||||||
|
%% An alias for path/4, but more convenient when needing a path from a closed
|
||||||
|
%% package_id().
|
||||||
|
|
||||||
|
ppath(Type, {Realm, Name, Version}) ->
|
||||||
|
path(Type, Realm, Name, Version).
|
||||||
|
|
||||||
|
|
||||||
-spec force_dir(Path) -> Result
|
-spec force_dir(Path) -> Result
|
||||||
when Path :: file:filename(),
|
when Path :: file:filename(),
|
||||||
Result :: ok
|
Result :: ok
|
||||||
@ -134,6 +170,20 @@ force_dir(Path) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec mktemp_dir(Package) -> Result
|
||||||
|
when Package :: zx:package(),
|
||||||
|
Result :: {ok, TempDir :: file:filename()}
|
||||||
|
| {error, Reason :: file:posix()}.
|
||||||
|
|
||||||
|
mktemp_dir({Realm, Name}) ->
|
||||||
|
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
|
||||||
|
TempDir = filename:join(path(etc, Realm, Name), Rand),
|
||||||
|
case force_dir(TempDir) of
|
||||||
|
ok -> {ok, TempDir};
|
||||||
|
Error -> Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec hosts_cache_file(zx:realm()) -> file:filename().
|
-spec hosts_cache_file(zx:realm()) -> file:filename().
|
||||||
%% @private
|
%% @private
|
||||||
%% Given a Realm name, construct a realm's .hosts filename and return it.
|
%% Given a Realm name, construct a realm's .hosts filename and return it.
|
||||||
|
|||||||
@ -11,11 +11,13 @@
|
|||||||
-license("GPL-3.0").
|
-license("GPL-3.0").
|
||||||
|
|
||||||
-export([initialize/2, assimilate/1, set_dep/1, set_version/1,
|
-export([initialize/2, assimilate/1, set_dep/1, set_version/1,
|
||||||
list_realms/0, list_packages/1, list_versions/1, add_realm/1,
|
list_realms/0, list_packages/1, list_versions/1,
|
||||||
drop_dep/1, drop_key/1, drop_realm/1, verup/1, package/1,
|
drop_dep/1, verup/1, package/1,
|
||||||
|
add_realm/1, drop_realm/1,
|
||||||
|
takeover/1, abdicate/1,
|
||||||
create_plt/0, dialyze/0,
|
create_plt/0, dialyze/0,
|
||||||
grow_a_pair/0, drop_key/1,
|
grow_a_pair/0, drop_key/1,
|
||||||
create_user/2, create_realm/0, create_realmfile/1]).
|
create_user/2, create_realm/0, create_realmfile/2]).
|
||||||
|
|
||||||
-include("zx_logger.hrl").
|
-include("zx_logger.hrl").
|
||||||
|
|
||||||
@ -27,13 +29,8 @@
|
|||||||
when Type :: app | lib,
|
when Type :: app | lib,
|
||||||
PackageString :: string().
|
PackageString :: string().
|
||||||
%% @private
|
%% @private
|
||||||
%% Initialize an application in the local directory based on the PackageID provided.
|
%% Initialize an application in the local directory based on the PackageID provided
|
||||||
%% This function does not care about the name of the current directory and leaves
|
%% and interaction with the user to determine a few details.
|
||||||
%% providing a complete, proper and accurate PackageID.
|
|
||||||
%% This function will check the current `lib/' directory for zomp-style dependencies.
|
|
||||||
%% If this is not the intended function or if there are non-compliant directory names
|
|
||||||
%% in `lib/' then the project will need to be rearranged to become zomp compliant or
|
|
||||||
%% the `deps' section of the resulting meta file will need to be manually updated.
|
|
||||||
|
|
||||||
initialize(Type, RawPackageString) ->
|
initialize(Type, RawPackageString) ->
|
||||||
ok =
|
ok =
|
||||||
@ -41,7 +38,7 @@ initialize(Type, RawPackageString) ->
|
|||||||
false -> ok;
|
false -> ok;
|
||||||
true -> error_exit("This project is already Zompified.", ?LINE)
|
true -> error_exit("This project is already Zompified.", ?LINE)
|
||||||
end,
|
end,
|
||||||
PackageID =
|
PackageID = {Realm, Name, _} =
|
||||||
case zx_lib:package_id(RawPackageString) of
|
case zx_lib:package_id(RawPackageString) of
|
||||||
{ok, {R, N, {z, z, z}}} ->
|
{ok, {R, N, {z, z, z}}} ->
|
||||||
{R, N, {0, 1, 0}};
|
{R, N, {0, 1, 0}};
|
||||||
@ -54,19 +51,58 @@ initialize(Type, RawPackageString) ->
|
|||||||
{error, invalid_package_string} ->
|
{error, invalid_package_string} ->
|
||||||
error_exit("Invalid package string: ~tp", [RawPackageString], ?LINE)
|
error_exit("Invalid package string: ~tp", [RawPackageString], ?LINE)
|
||||||
end,
|
end,
|
||||||
{ok, PackageString} = zx_lib:package_string(PackageID),
|
case package_exists(PackageID) of
|
||||||
ok = check_package_conflict(PackageID, PackageString),
|
false ->
|
||||||
ok = log(info, "Initializing ~s...", [PackageString]),
|
Prefix = solicit_prefix(),
|
||||||
Prefix = solicit_prefix(),
|
initialize(Type, PackageID, Prefix);
|
||||||
|
true ->
|
||||||
|
PackageName = zx_lib:package_string({Realm, Name, {z, z, z}}),
|
||||||
|
Message = "Package ~tp already exists. Try another.",
|
||||||
|
error_exit(Message, [PackageName], ?LINE)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
initialize(app, PackageID, Prefix) ->
|
||||||
|
Instructions =
|
||||||
|
"The OTP application controller has to know what module to call start/2 on to "
|
||||||
|
"start your program.~n"
|
||||||
|
"If this is not an OTP application or if there is some special setting you "
|
||||||
|
"need then ignore this by just pressing [ENTER] to bypass this and go back "
|
||||||
|
"later and edit the 'mod' attribute in your ebin/[AppName].app file by hand.~n"
|
||||||
|
"this blank.~n"
|
||||||
|
"Enter the name of your main/start interface module where the application "
|
||||||
|
"callback start/2 has been defined.~n",
|
||||||
|
ok = io:format(Instructions),
|
||||||
|
case zx_tty:get_input() of
|
||||||
|
"" ->
|
||||||
|
initialize(lib, PackageID, Prefix, none);
|
||||||
|
String ->
|
||||||
|
case zx_lib:valid_lower0_9(String) of
|
||||||
|
true ->
|
||||||
|
AppStart = {list_to_atom(String), []},
|
||||||
|
initialize(app, PackageID, Prefix, AppStart);
|
||||||
|
false ->
|
||||||
|
Message = "The name \"~ts\" doesn't seem valid. Try \"[a-z_]*\".~n",
|
||||||
|
ok = io:format(Message, String),
|
||||||
|
initialize(app, PackageID, Prefix)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
initialize(lib, PackageID, Prefix) ->
|
||||||
|
initialize(lib, PackageID, Prefix, none).
|
||||||
|
|
||||||
|
|
||||||
|
initialize(Type, PackageID, Prefix, AppStart) ->
|
||||||
ok = update_source_vsn(element(3, PackageID)),
|
ok = update_source_vsn(element(3, PackageID)),
|
||||||
ok = update_app_file(PackageID),
|
ok = initialize_app_file(PackageID, AppStart),
|
||||||
MetaList =
|
MetaList =
|
||||||
[{package_id, PackageID},
|
[{package_id, PackageID},
|
||||||
{deps, []},
|
{deps, []},
|
||||||
{type, Type},
|
{type, Type},
|
||||||
{prefix, Prefix}],
|
{prefix, Prefix},
|
||||||
|
{appmod, AppStart}],
|
||||||
Meta = maps:from_list(MetaList),
|
Meta = maps:from_list(MetaList),
|
||||||
ok = zx_lib:write_project_meta(Meta),
|
ok = zx_lib:write_project_meta(Meta),
|
||||||
|
{ok, PackageString} = zx_lib:package_string(PackageID),
|
||||||
ok = log(info, "Project ~tp initialized.", [PackageString]),
|
ok = log(info, "Project ~tp initialized.", [PackageString]),
|
||||||
Message =
|
Message =
|
||||||
"~nNOTICE:~n"
|
"~nNOTICE:~n"
|
||||||
@ -76,36 +112,54 @@ initialize(Type, RawPackageString) ->
|
|||||||
io:format(Message).
|
io:format(Message).
|
||||||
|
|
||||||
|
|
||||||
-spec check_package_conflict(zx:package_id(), string()) -> ok.
|
-spec package_exists(zx:package_id()) -> boolean().
|
||||||
%% @private
|
%% @private
|
||||||
%% Check the realm's upstream for the existence of a package that already has the same
|
%% Check the realm's upstream for the existence of a package that already has the same
|
||||||
%% name, or the name of any modules in src/ and report them to the user. Give the user
|
%% name, or the name of any modules in src/ and report them to the user. Give the user
|
||||||
%% a chance to change their package's name or ignore the conflict, and report all module
|
%% a chance to change their package's name or ignore the conflict, and report all module
|
||||||
%% naming conflicts.
|
%% naming conflicts.
|
||||||
|
|
||||||
check_package_conflict(_PackageID, _PackageString) ->
|
package_exists(PackageID) ->
|
||||||
log(info, "TODO: This is where the intended realm is checked for conflicts "
|
ok = log(info, "TODO: This is where the intended realm is checked for conflicts "
|
||||||
"and the user is given a chance to rename or ignore the conflict. "
|
"and the user is given a chance to rename or ignore the conflict. "
|
||||||
"This check will have to wait for the network protocol fix.").
|
"This check will have to wait for the network protocol fix."),
|
||||||
|
ok = log(info, "Pretending that the existence of ~tp was checked...", [PackageID]),
|
||||||
|
false.
|
||||||
|
|
||||||
|
|
||||||
-spec solicit_prefix() -> ok.
|
-spec solicit_prefix() -> string().
|
||||||
%% @private
|
%% @private
|
||||||
%% Most Erlang projects outside of the core distribution evolve a prefix of some sort
|
%% Get a valid module prefix to use as a namespace for new modules.
|
||||||
%% to namespace their work from other projects (or deliberately mimic another project's
|
|
||||||
%% prefix in the case that a new project is meant to augment, but not alter, an already
|
|
||||||
%% existing one).
|
|
||||||
%% A prefix is decided upon or disregarded here and stored in the meta file. The user
|
|
||||||
%% is given the option to update module names now (to include modifying call sites
|
|
||||||
%% in project code automatically -- while providing ample warnings about breaking
|
|
||||||
%% external code).
|
|
||||||
%% Just like with check_package_conflict/2, this procedure gives the user a chance to
|
|
||||||
%% ignore all warnings and just go.
|
|
||||||
|
|
||||||
solicit_prefix() ->
|
solicit_prefix() ->
|
||||||
ok = log(info, "Will solicit a prefix here. Just returning \"zz\" right now. Hah!"),
|
Instructions =
|
||||||
"zz".
|
"~nPICKING A PREFIX~n"
|
||||||
|
"Most Erlang applications have a prefix on the front of their modules. This "
|
||||||
|
"is a way of namespacing modules from different applications so they don't "
|
||||||
|
"conflict in very large execution environments.~n"
|
||||||
|
"A common way of coming up with a prefix is to make a lower-case acronym of "
|
||||||
|
"your application name and add an underscore at the end, unless your app "
|
||||||
|
"name is so short that it isn't a problem to use it as its own prefix.~n"
|
||||||
|
"For example: the prefix for all ZX modules is 'zx_', and the prefix for "
|
||||||
|
"otpr-example_server is 'es_'.~n"
|
||||||
|
"If you already have a prefix, just type it here (including the trailing "
|
||||||
|
"underscore if there is one). If you are making up a new one in an existing "
|
||||||
|
"project you'll need to rename your modules and fix up call sites with sed.~n"
|
||||||
|
"Enter a blank prefix (just [ENTER]) to ignore this and use no prefix.~n",
|
||||||
|
ok = io:format(Instructions),
|
||||||
|
case zx_tty:get_input() of
|
||||||
|
"" ->
|
||||||
|
"";
|
||||||
|
Prefix ->
|
||||||
|
case zx_lib:valid_lower0_9(Prefix) of
|
||||||
|
true ->
|
||||||
|
Prefix;
|
||||||
|
false ->
|
||||||
|
Message = "The string \"~tp\" is problematic. Try \"[a-z]*_\".~n",
|
||||||
|
ok = io:format(Message, [Prefix]),
|
||||||
|
solicit_prefix()
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
-spec update_source_vsn(zx:version()) -> ok.
|
-spec update_source_vsn(zx:version()) -> ok.
|
||||||
%% @private
|
%% @private
|
||||||
@ -128,17 +182,25 @@ update_source_vsn(Version) ->
|
|||||||
log(info, "Source version attributes set").
|
log(info, "Source version attributes set").
|
||||||
|
|
||||||
|
|
||||||
-spec update_app_file(zx:package_id()) -> ok.
|
-spec update_app_vsn(zx:name(), zx:version()) -> ok.
|
||||||
|
|
||||||
|
update_app_vsn(Name, Version) ->
|
||||||
|
{ok, VersionString} = zx_lib:version_to_string(Version),
|
||||||
|
AppFile = filename:join("ebin", Name ++ ".app"),
|
||||||
|
{ok, [{application, AppName, OldAppData}]} = file:consult(AppFile),
|
||||||
|
NewAppData = lists:keystore(vsn, 1, OldAppData, {vsn, VersionString}),
|
||||||
|
zx_lib:write_terms(AppFile, [{application, AppName, NewAppData}]).
|
||||||
|
|
||||||
|
|
||||||
|
-spec initialize_app_file(PackageID, AppStart) -> ok
|
||||||
|
when PackageID :: zx:package_id(),
|
||||||
|
AppStart :: {StartMod :: module(), Args :: term()}
|
||||||
|
| none.
|
||||||
%% @private
|
%% @private
|
||||||
%% Update the app file or create it if it is missing.
|
%% Update the app file or create it if it is missing.
|
||||||
%% TODO: If the app file is missing, interpret the src/*app.src file correctly.
|
%% TODO: If the app file is missing and an app/*.src exists, interpret that.
|
||||||
%% Should really pull a few pages out of the rebar/erland.mk books on this,
|
|
||||||
%% as they've done all the hard pioneering work already.
|
|
||||||
%% TODO: Interactively determine whether the main module is the name, or the prefix
|
|
||||||
%% is the name, or the name is the prefix, or the name is the description, etc.
|
|
||||||
%% before writing anything out.
|
|
||||||
|
|
||||||
update_app_file({_, Name, Version}) ->
|
initialize_app_file({_, Name, Version}, AppStart) ->
|
||||||
{ok, VersionString} = zx_lib:version_to_string(Version),
|
{ok, VersionString} = zx_lib:version_to_string(Version),
|
||||||
AppName = list_to_atom(Name),
|
AppName = list_to_atom(Name),
|
||||||
AppFile = filename:join("ebin", Name ++ ".app"),
|
AppFile = filename:join("ebin", Name ++ ".app"),
|
||||||
@ -157,13 +219,24 @@ update_app_file({_, Name, Version}) ->
|
|||||||
Grep = "grep -oP '^-module\\(\\K[^)]+' src/* | cut -d: -f2",
|
Grep = "grep -oP '^-module\\(\\K[^)]+' src/* | cut -d: -f2",
|
||||||
Modules = [list_to_atom(M) || M <- string:lexemes(os:cmd(Grep), "\n")],
|
Modules = [list_to_atom(M) || M <- string:lexemes(os:cmd(Grep), "\n")],
|
||||||
Properties =
|
Properties =
|
||||||
[{vsn, VersionString},
|
case (AppStart == none) or lists:keymember(mod, 1, RawAppData) of
|
||||||
{modules, Modules},
|
true ->
|
||||||
{mod, {AppName, []}}],
|
[{vsn, VersionString},
|
||||||
|
{modules, Modules}];
|
||||||
|
false ->
|
||||||
|
[{vsn, VersionString},
|
||||||
|
{modules, Modules},
|
||||||
|
{mod, AppStart}]
|
||||||
|
end,
|
||||||
Store = fun(T, L) -> lists:keystore(element(1, T), 1, L, T) end,
|
Store = fun(T, L) -> lists:keystore(element(1, T), 1, L, T) end,
|
||||||
AppData = lists:foldl(Store, RawAppData, Properties),
|
AppData = lists:foldl(Store, RawAppData, Properties),
|
||||||
AppProfile = {application, AppName, AppData},
|
AppProfile = {application, AppName, AppData},
|
||||||
ok = log(info, "Writing app file: ~ts~n~tp", [AppFile, AppProfile]),
|
ok = log(info, "Writing app file: ~ts", [AppFile]),
|
||||||
|
Notice =
|
||||||
|
"NOTE: From this point on ZX will only update the module list and version "
|
||||||
|
"number of your .app file. Any additional changes (start module/args, start "
|
||||||
|
"phases, etc.) will need to be done by hand.~n",
|
||||||
|
ok = io:format(Notice),
|
||||||
zx_lib:write_terms(AppFile, [AppProfile]).
|
zx_lib:write_terms(AppFile, [AppProfile]).
|
||||||
|
|
||||||
|
|
||||||
@ -318,6 +391,8 @@ update_version(Realm, Name, OldVersion, NewVersion, OldMeta) ->
|
|||||||
PackageID = {Realm, Name, NewVersion},
|
PackageID = {Realm, Name, NewVersion},
|
||||||
NewMeta = maps:put(package_id, PackageID, OldMeta),
|
NewMeta = maps:put(package_id, PackageID, OldMeta),
|
||||||
ok = zx_lib:write_project_meta(NewMeta),
|
ok = zx_lib:write_project_meta(NewMeta),
|
||||||
|
ok = update_source_vsn(NewVersion),
|
||||||
|
ok = update_app_vsn(Name, NewVersion),
|
||||||
{ok, OldVS} = zx_lib:version_to_string(OldVersion),
|
{ok, OldVS} = zx_lib:version_to_string(OldVersion),
|
||||||
{ok, NewVS} = zx_lib:version_to_string(NewVersion),
|
{ok, NewVS} = zx_lib:version_to_string(NewVersion),
|
||||||
log(info, "Version changed from ~s to ~s.", [OldVS, NewVS]).
|
log(info, "Version changed from ~s to ~s.", [OldVS, NewVS]).
|
||||||
@ -339,7 +414,6 @@ list_realms() ->
|
|||||||
%% them to stdout.
|
%% them to stdout.
|
||||||
|
|
||||||
list_packages(Realm) ->
|
list_packages(Realm) ->
|
||||||
ok = zx:start(),
|
|
||||||
case zx_daemon:list_packages(Realm) of
|
case zx_daemon:list_packages(Realm) of
|
||||||
{ok, []} ->
|
{ok, []} ->
|
||||||
log(info, "Realm ~tp has no packages available.", [Realm]);
|
log(info, "Realm ~tp has no packages available.", [Realm]);
|
||||||
@ -415,22 +489,6 @@ add_realm(Path) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec add_realm(Path, Data) -> ok
|
|
||||||
when Path :: file:filename(),
|
|
||||||
Data :: binary().
|
|
||||||
|
|
||||||
add_realm(Path, Data) ->
|
|
||||||
case erl_tar:extract({binary, Data}, [compressed, {cwd, zx_lib:zomp_dir()}]) of
|
|
||||||
ok ->
|
|
||||||
{Realm, _} = string:take(filename:basename(Path), ".", true),
|
|
||||||
log(info, "Realm ~ts is now visible to this system.", [Realm]);
|
|
||||||
{error, invalid_tar_checksum} ->
|
|
||||||
error_exit("~ts is not a valid realm file.", [Path], ?LINE);
|
|
||||||
{error, eof} ->
|
|
||||||
error_exit("~ts is not a valid realm file.", [Path], ?LINE)
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec drop_dep(zx:package_id()) -> ok.
|
-spec drop_dep(zx:package_id()) -> ok.
|
||||||
%% @private
|
%% @private
|
||||||
%% Remove the indicate dependency from the local project's zomp.meta record.
|
%% Remove the indicate dependency from the local project's zomp.meta record.
|
||||||
@ -458,59 +516,6 @@ drop_dep(PackageID) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec drop_realm(zx:realm()) -> ok.
|
|
||||||
|
|
||||||
drop_realm(Realm) ->
|
|
||||||
ok = file:set_cwd(zx_lib:zomp_dir()),
|
|
||||||
RealmConf = zx_lib:realm_conf(Realm),
|
|
||||||
case filelib:is_regular(RealmConf) of
|
|
||||||
true ->
|
|
||||||
Message =
|
|
||||||
"~n"
|
|
||||||
" WARNING: Are you SURE you want to remove realm ~ts?~n"
|
|
||||||
" (Only \"Y\" will confirm this action.)~n",
|
|
||||||
ok = io:format(Message, [Realm]),
|
|
||||||
case zx_tty:get_input() of
|
|
||||||
"Y" ->
|
|
||||||
ok = file:delete(RealmConf),
|
|
||||||
ok = drop_prime(Realm),
|
|
||||||
ok = clear_keys(Realm),
|
|
||||||
log(info, "All traces of realm ~ts have been removed.");
|
|
||||||
_ ->
|
|
||||||
log(info, "Aborting.")
|
|
||||||
end;
|
|
||||||
false ->
|
|
||||||
ok = log(warning, "Realm conf ~ts not found.", [RealmConf]),
|
|
||||||
clear_keys(Realm)
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec drop_prime(zx:realm()) -> ok.
|
|
||||||
|
|
||||||
drop_prime(Realm) ->
|
|
||||||
Path = "zomp.conf",
|
|
||||||
case file:consult(Path) of
|
|
||||||
{ok, Conf} ->
|
|
||||||
{managed, Primes} = lists:keyfind(managed, 1, Conf),
|
|
||||||
NewPrimes = lists:delete(Realm, Primes),
|
|
||||||
NewConf = lists:keystore(managed, 1, Primes, {managed, NewPrimes}),
|
|
||||||
ok = zx_lib:write_terms(Path, NewConf),
|
|
||||||
log(info, "Ensuring ~ts is not a prime in ~ts", [Realm, Path]);
|
|
||||||
{error, enoent} ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec clear_keys(zx:realm()) -> ok.
|
|
||||||
|
|
||||||
clear_keys(Realm) ->
|
|
||||||
KeyDir = filename:join([zx_lib:zomp_dir(), "key", Realm]),
|
|
||||||
case filelib:is_dir(KeyDir) of
|
|
||||||
true -> zx_lib:rm_rf(KeyDir);
|
|
||||||
false -> log(warning, "Keydir ~ts not found", [KeyDir])
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec verup(Level) -> ok
|
-spec verup(Level) -> ok
|
||||||
when Level :: string().
|
when Level :: string().
|
||||||
%% @private
|
%% @private
|
||||||
@ -784,8 +789,7 @@ create_realm() ->
|
|||||||
Realm = zx_tty:get_input(),
|
Realm = zx_tty:get_input(),
|
||||||
case zx_lib:valid_lower0_9(Realm) of
|
case zx_lib:valid_lower0_9(Realm) of
|
||||||
true ->
|
true ->
|
||||||
RealmFile = filename:join(zx_lib:zomp_dir(), Realm ++ ".realm"),
|
case realm_exists(Realm) of
|
||||||
case filelib:is_regular(RealmFile) of
|
|
||||||
false ->
|
false ->
|
||||||
create_realm(Realm);
|
create_realm(Realm);
|
||||||
true ->
|
true ->
|
||||||
@ -964,71 +968,72 @@ create_realm(Realm, Address, Port, UserName, Email) ->
|
|||||||
create_realm(Realm, Address, Port, UserName, Email, RealName) ->
|
create_realm(Realm, Address, Port, UserName, Email, RealName) ->
|
||||||
ok = io:format("~nGenerating keys. This might take a while, so settle in...~n"),
|
ok = io:format("~nGenerating keys. This might take a while, so settle in...~n"),
|
||||||
KeyName = UserName ++ "-root",
|
KeyName = UserName ++ "-root",
|
||||||
|
ok = make_realm_dirs(Realm),
|
||||||
ok = zx_key:generate_rsa({Realm, KeyName}),
|
ok = zx_key:generate_rsa({Realm, KeyName}),
|
||||||
Timestamp = calendar:now_to_universal_time(erlang:timestamp()),
|
|
||||||
RealmConf =
|
RealmConf =
|
||||||
[{realm, Realm},
|
[{realm, Realm},
|
||||||
{prime, {Address, Port}},
|
{prime, {Address, Port}},
|
||||||
{sysop, UserName},
|
{sysop, UserName},
|
||||||
{key, KeyName}],
|
{key, KeyName}],
|
||||||
UserFile =
|
UserConf =
|
||||||
[{realm, Realm},
|
[{realm, Realm},
|
||||||
{username, UserName},
|
{username, UserName},
|
||||||
{realmname, RealName},
|
{realmname, RealName},
|
||||||
{contact_info, {"email", Email}},
|
{contact_info, {"email", Email}},
|
||||||
{keys, [KeyName]}],
|
{keys, [KeyName]}],
|
||||||
|
ok = make_realm_dirs(Realm),
|
||||||
{ok, CWD} = file:get_cwd(),
|
RealmConfPath = filename:join(zx_lib:path(etc, Realm), "realm.conf"),
|
||||||
ok = file:set_cwd(zx_lib:path(etc)),
|
ok = zx_lib:write_terms(RealmConfPath, RealmConf),
|
||||||
PubKey = zx_key:name(pub, KeyName),
|
UserConfPath = filename:join(zx_lib:path(etc, Realm), UserName ++ ".user"),
|
||||||
ConfFile = filename:join(Realm, "realm.conf"),
|
ok = zx_lib:write_terms(UserConfPath, UserConf),
|
||||||
ok = file:make_dir(Realm),
|
ok = create_realmfile(Realm, "."),
|
||||||
ok = zx_lib:write_terms(ConfFile, RealmConf),
|
ZRF = Realm ++ ".zrf",
|
||||||
ZRF =
|
|
||||||
ok = erl_tar:create(ZRF, [ConfFile, PubKey], [compressed]),
|
|
||||||
|
|
||||||
|
|
||||||
Message =
|
Message =
|
||||||
"===========================================================================~n"
|
"===========================================================================~n"
|
||||||
"DONE!~n"
|
"DONE!~n"
|
||||||
"~n"
|
"~n"
|
||||||
"The realm ~ts has been created and is accessible from the current system.~n"
|
"The realm ~tp has been created and is accessible from the current system.~n"
|
||||||
"Three configuration bundles have been created in the current directory:~n"
|
|
||||||
"~n"
|
"~n"
|
||||||
" 1. ~ts ~n"
|
"Other zomp nodes and zx users will need the new realm file, ~ts, to~n"
|
||||||
"This is the PRIVATE realm file you will need to install on the realm's prime~n"
|
"access the realm. It does not include any public keys.~n"
|
||||||
"node. It includes the your (the sysop's) public key.~n"
|
|
||||||
"~n"
|
"~n"
|
||||||
" 2. ~ts ~n"
|
"On the PRIME NODE you need to run two command:~n"
|
||||||
"This file is the PUBLIC realm file other zomp nodes and zx users will need~n"
|
"1. `zx add realm ~ts` to install the new .zrf there~n"
|
||||||
"to access the realm. It does not include your (the sysop's) public key.~n"
|
"2. `zx make prime ~ts` to tell the node that it is prime for that realm~n"
|
||||||
"~n"
|
"~n"
|
||||||
" 3. ~ts ~n"
|
"On all ZX clients that want to access your new realm and on all subordinate~n"
|
||||||
"This is the bundle of ALL KEYS that are defined in this realm at the moment.~n"
|
"Zomp nodes the command `zx add realm ~ts` will need to be run.~n"
|
||||||
"~n"
|
"~n"
|
||||||
"Now you need to make copies of these three files and back them up.~n"
|
"How to distribute ~ts is up to you.~n"
|
||||||
"~n"
|
|
||||||
"On the PRIME NODE you need to run `zx add realm ~ts` and follow the prompts~n"
|
|
||||||
"to cause it to begin serving that realm as prime. (Node restart required.)~n"
|
|
||||||
"~n"
|
|
||||||
"On all zx CLIENTS that want to access your new realm and on all subordinate~n"
|
|
||||||
"MIRROR NODES the command `zx add realm ~ts` will need to be run.~n"
|
|
||||||
"The method of public realm file distribution (~ts) is up to you.~n"
|
|
||||||
"~n"
|
|
||||||
"~n"
|
|
||||||
"Public & Private key installation (if you need to recover them or perform~n"
|
|
||||||
"sysop functions from another computer) is `zx add keybundle ~ts`.~n"
|
|
||||||
"===========================================================================~n",
|
"===========================================================================~n",
|
||||||
Substitutions =
|
Substitutions = [Realm, ZRF, ZRF, Realm, ZRF, ZRF],
|
||||||
[Realm,
|
|
||||||
PrimeZRF, PublicZRF, KeyBundle,
|
|
||||||
PrimeZRF,
|
|
||||||
PublicZRF, PublicZRF,
|
|
||||||
KeyBundle],
|
|
||||||
io:format(Message, Substitutions).
|
io:format(Message, Substitutions).
|
||||||
|
|
||||||
|
|
||||||
-spec configure_zomp() - ok.
|
-spec realm_exists(zx:realm()) -> boolean().
|
||||||
|
%% @private
|
||||||
|
%% Checks for remnants of a realm.
|
||||||
|
|
||||||
|
realm_exists(Realm) ->
|
||||||
|
Dirs = [etc, var, tmp, log, key, zsp, lib],
|
||||||
|
Check = fun(D) -> filelib:is_file(zx_lib:path(D)) end,
|
||||||
|
Managed = lists:member(Realm, proplists:get_value(managed, zx_lib:read_sys_conf())),
|
||||||
|
Found = lists:any(Check, Dirs),
|
||||||
|
Managed or Found.
|
||||||
|
|
||||||
|
|
||||||
|
-spec make_realm_dirs(zx:realm()) -> ok.
|
||||||
|
%% @private
|
||||||
|
%% This is an unsafe operation. The caller must be sure realm_exists/1 returns false
|
||||||
|
%% or be certain some other way that the file:make_sure/1 calls will succeed.
|
||||||
|
|
||||||
|
make_realm_dirs(Realm) ->
|
||||||
|
Dirs = [etc, var, tmp, log, key, zsp, lib],
|
||||||
|
Make = fun(D) -> ok = file:make_dir(zx_lib:path(D, Realm)) end,
|
||||||
|
lists:foreach(Make, Dirs).
|
||||||
|
|
||||||
|
|
||||||
|
-spec configure_zomp() -> ok.
|
||||||
|
|
||||||
configure_zomp() ->
|
configure_zomp() ->
|
||||||
ZompSettings =
|
ZompSettings =
|
||||||
@ -1040,54 +1045,84 @@ configure_zomp() ->
|
|||||||
io:format("~tp~n", [ZompSettings]).
|
io:format("~tp~n", [ZompSettings]).
|
||||||
|
|
||||||
|
|
||||||
-spec mktemp_dir(Prefix) -> Result
|
-spec create_realmfile(Realm, Dir) -> ok
|
||||||
when Prefix :: string(),
|
when Realm :: zx:realm(),
|
||||||
Result :: {ok, TempDir :: file:filename()}
|
Dir :: file:filename().
|
||||||
| {error, Reason :: file:posix()}.
|
|
||||||
|
|
||||||
mktemp_dir(Prefix) ->
|
create_realmfile(Realm, Dir) ->
|
||||||
Rand = integer_to_list(binary:decode_unsigned(crypto:strong_rand_bytes(8)), 36),
|
RealmConf = zx_lib:load_realm_conf(Realm),
|
||||||
TempPath = filename:basedir(user_cache, Prefix),
|
ok = log(info, "Realm found, creating realm file..."),
|
||||||
TempDir = filename:join(TempPath, Rand),
|
KeyName = proplists:get_value(key, RealmConf),
|
||||||
Result1 = filelib:ensure_dir(TempDir),
|
PubKeyPath = zx_key:name(pub, KeyName),
|
||||||
Result2 = file:make_dir(TempDir),
|
{ok, PubDER} = file:read_file(PubKeyPath),
|
||||||
case {Result1, Result2} of
|
Blob = term_to_binary({RealmConf, PubDER}),
|
||||||
{ok, ok} -> {ok, TempDir};
|
ZRF = filename:join(Dir, Realm ++ ".zrf"),
|
||||||
{ok, Error} -> Error;
|
ok = file:write_file(ZRF, Blob),
|
||||||
{Error, _} -> Error
|
log(info, "Realm conf file written to ~ts", [ZRF]).
|
||||||
|
|
||||||
|
|
||||||
|
-spec add_realm(Path, Data) -> ok
|
||||||
|
when Path :: file:filename(),
|
||||||
|
Data :: binary().
|
||||||
|
|
||||||
|
add_realm(Path, Data) ->
|
||||||
|
case erl_tar:extract({binary, Data}, [compressed, {cwd, zx_lib:zomp_dir()}]) of
|
||||||
|
ok ->
|
||||||
|
{Realm, _} = string:take(filename:basename(Path), ".", true),
|
||||||
|
log(info, "Realm ~ts is now visible to this system.", [Realm]);
|
||||||
|
{error, invalid_tar_checksum} ->
|
||||||
|
error_exit("~ts is not a valid realm file.", [Path], ?LINE);
|
||||||
|
{error, eof} ->
|
||||||
|
error_exit("~ts is not a valid realm file.", [Path], ?LINE)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec create_realmfile(zx:realm()) -> no_return().
|
-spec drop_realm(zx:realm()) -> ok.
|
||||||
|
|
||||||
create_realmfile(Realm) ->
|
drop_realm(Realm) ->
|
||||||
RealmConf = zx_lib:load_realm_conf(Realm),
|
case realm_exists(Realm) of
|
||||||
ok = log(info, "Realm found, creating realm file..."),
|
true ->
|
||||||
{revision, Revision} = lists:keyfind(revision, 1, RealmConf),
|
Message =
|
||||||
{realm_keys, RealmKeys} = lists:keyfind(realm_keys, 1, RealmConf),
|
"~n"
|
||||||
{package_keys, PackageKeys} = lists:keyfind(package_keys, 1, RealmConf),
|
" WARNING: Are you SURE you want to remove realm ~ts?~n"
|
||||||
RealmKeyIDs = [element(1, K) || K <- RealmKeys],
|
" (Only \"Y\" will confirm this action.)~n",
|
||||||
PackageKeyIDs = [element(1, K) || K <- PackageKeys],
|
ok = io:format(Message, [Realm]),
|
||||||
create_realmfile(Realm, Revision, RealmKeyIDs, PackageKeyIDs).
|
case zx_tty:get_input() of
|
||||||
|
"Y" ->
|
||||||
|
Dirs = [etc, var, tmp, log, key, zsp, lib],
|
||||||
|
RM = fun(D) -> ok = zx_lib:rm_rf(zx_lib:path(D, Realm)) end,
|
||||||
|
ok = lists:foreach(RM, Dirs),
|
||||||
|
ok = abdicate(Realm),
|
||||||
|
log(info, "All traces of realm ~ts have been removed.");
|
||||||
|
_ ->
|
||||||
|
log(info, "Aborting.")
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
log(info, "Could not find any trace of realm ~tp", [Realm])
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec create_realmfile(Realm, Revision, RealmKeyIDs, PackageKeyIDs) -> ok
|
-spec takeover(zx:realm()) -> ok.
|
||||||
when Realm :: zx:realm(),
|
%% @private
|
||||||
Revision :: non_neg_integer(),
|
%% Assume responsibilities as the prime node for the given realm. Only works if
|
||||||
RealmKeyIDs :: [zx:key_id()],
|
%% the realm exists, of course.
|
||||||
PackageKeyIDs :: [zx:key_id()].
|
|
||||||
|
|
||||||
create_realmfile(Realm, Revision, RealmKeyIDs, PackageKeyIDs) ->
|
takeover(Realm) ->
|
||||||
{ok, CWD} = file:get_cwd(),
|
SysConf = zx_conf_sys:load(),
|
||||||
ok = file:set_cwd(zx_lib:zomp_dir()),
|
case zx_conf_sys:add_managed(Realm, SysConf) of
|
||||||
KeyPath = fun({R, K}) -> filename:join(["key", R, K ++ ".pub.der"]) end,
|
{ok, NewConf} -> zx_conf_sys:save(NewConf);
|
||||||
RealmKeyPaths = lists:map(KeyPath, RealmKeyIDs),
|
{error, unconfigured} -> log(error, "Cannot take over an unconfigured realm.")
|
||||||
PackageKeyPaths = lists:map(KeyPath, PackageKeyIDs),
|
end.
|
||||||
Targets = [zx_lib:realm_conf(Realm) | RealmKeyPaths ++ PackageKeyPaths],
|
|
||||||
OutFile = filename:join(CWD, Realm ++ "." ++ integer_to_list(Revision) ++ ".zrf"),
|
|
||||||
ok = erl_tar:create(OutFile, Targets, [compressed]),
|
-spec abdicate(zx:realm()) -> ok.
|
||||||
ok = log(info, "Realm conf file written to ~ts", [OutFile]),
|
|
||||||
halt(0).
|
abdicate(Realm) ->
|
||||||
|
SysConf = zx_conf_sys:load(),
|
||||||
|
case zx_conf_sys:rem_managed(Realm, SysConf) of
|
||||||
|
{ok, NewConf} -> zx_conf_sys:save(NewConf);
|
||||||
|
{error, unmanaged} -> log(error, "Cannot abdicate an unmanaged realm.")
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
zx_dev
2
zx_dev
@ -12,4 +12,4 @@ export ZX_DIR="$ZOMP_DIR/lib/otpr/zx/$VERSION"
|
|||||||
pushd "$ZX_DIR" > /dev/null
|
pushd "$ZX_DIR" > /dev/null
|
||||||
./make_zx
|
./make_zx
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
erl -pa "$ZX_DIR/ebin" -run zx run $@
|
erl -noshell -pa "$ZX_DIR/ebin" -run zx do $@
|
||||||
|
|||||||
15
zxh_dev
Executable file
15
zxh_dev
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pushd $(dirname $BASH_SOURCE) > /dev/null
|
||||||
|
ZX_DEV_ROOT=$PWD
|
||||||
|
popd > /dev/null
|
||||||
|
export ZOMP_DIR="$ZX_DEV_ROOT/tester"
|
||||||
|
rm -rf "$ZOMP_DIR"
|
||||||
|
cp -r "$ZX_DEV_ROOT/zomp" "$ZOMP_DIR"
|
||||||
|
VERSION=$(cat "$ZOMP_DIR/etc/version.txt")
|
||||||
|
export ZX_DIR="$ZOMP_DIR/lib/otpr/zx/$VERSION"
|
||||||
|
|
||||||
|
pushd "$ZX_DIR" > /dev/null
|
||||||
|
./make_zx
|
||||||
|
popd > /dev/null
|
||||||
|
erl -pa "$ZX_DIR/ebin" -run zx do $@
|
||||||
Loading…
x
Reference in New Issue
Block a user