This commit is contained in:
Craig Everett 2017-12-06 00:48:38 +09:00
parent 58aafaf692
commit 8476f3a89a

310
zx
View File

@ -87,10 +87,60 @@ start(["set", "dep", PackageString]) ->
set_dep(PackageID);
start(["set", "version", VersionString]) ->
set_version(VersionString);
start(["list", "realms"]) ->
list_realms();
start(["list", "packages", Realm]) ->
case valid_lower0_9(Realm) of
true ->
list_packages(Realm);
false ->
ok = log(error, "Bad realm name."),
halt(1)
end;
start(["list", "versions", Package]) ->
case string:lexemes(Package, "-") of
[Realm, Name] ->
list_versions({Realm, Name});
_ ->
ok = log(error, "Bad package name."),
halt(1)
end;
start(["list", "pending", Package]) ->
case string:lexemes(Package, "-") of
[Realm, Name] ->
list_pending({Realm, Name});
_ ->
ok = log(error, "Bad package name."),
halt(1)
end;
start(["list", "resigns", Realm]) ->
case valid_lower0_9(Realm) of
true ->
list_resigns(Realm);
false ->
ok = log(error, "Bad realm name."),
halt(1)
end;
start(["add", "realm", RealmFile]) ->
add_realm(RealmFile);
start(["add", "package", PackageName]) ->
add_package(PackageName);
start(["add", "packager", Package, UserName]) ->
add_packager(Package, UserName);
start(["add", "maintainer", Package, UserName]) ->
add_maintainer(Package, UserName);
start(["review", PackageString]) ->
PackageID = package_id(PackageString),
review(PackageID);
start(["approve", PackageString]) ->
PackageID = package_id(PackageString),
approve(PackageID);
start(["reject", PackageString]) ->
PackageID = package_id(PackageString),
reject(PackageID);
start(["resign", PackageString]) ->
PackageID = package_id(PackageString),
resign(PackageID);
start(["drop", "dep", PackageString]) ->
PackageID = package_id(PackageString),
drop_dep(PackageID);
@ -548,6 +598,104 @@ update_version(Realm, Name, OldVersion, NewVersion, OldMeta) ->
%%% List Functions
-spec list_realms() -> no_return().
%% @private
%% List all currently configured realms. The definition of a "configured realm" is a
%% realm for which a .realm file exists in ~/.zomp/. The realms will be printed to
%% stdout and the program will exit.
list_realms() ->
Pattern = filename:join(zomp_dir(), "*.realm"),
RealmFiles = filelib:wildcard(Pattern),
Realms = [filename:basename(RF, ".realm") || RF <- RealmFiles],
ok = lists:foreach(fun(R) -> io:format("~ts~n", [R]) end, Realms),
halt(0).
-spec list_packages(realm()) -> no_return().
%% @private
%% Contact the indicated realm and query it for a list of registered packages and print
%% them to stdout.
list_packages(Realm) ->
Socket = connect_user(Realm),
ok = send(Socket, {list, Realm}),
case recv_or_die(Socket) of
{ok, []} ->
ok = log(info, "Realm ~tp has no packages available.", [Realm]),
halt(0);
{ok, Packages} ->
Print = fun({R, N}) -> io:format("~ts-~ts~n", [R, N]) end,
ok = lists:foreach(Print, Packages),
halt(0);
end.
-spec list_versions(package()) -> no_return().
list_versions(Package = {Realm, Name}) ->
ok = valid_package(Package),
Socket = connect_user(Realm),
ok = send(Socket, {list, Realm, Name}),
case recv_or_die(Socket) of
{ok, []} ->
Message = "Package ~ts-~ts has no versions available.",
ok = log(info, Message, [Realm, Name]),
halt(0);
{ok, Versions} ->
Print =
fun(Version) ->
PackageString = package_string({Realm, Name, Version}),
io:format("~ts~n", [PackageString])
end,
ok = lists:foreach(Print, Versions),
halt(0)
end.
-spec list_pending(package()) -> no_return().
list_pending(Package = {Realm, Name}) ->
ok = valid_package(Package),
Socket = connect_user(Realm),
ok = send(Socket, {pending, Package}),
case recv_or_die(Socket) of
{ok, []} ->
Message = "Package ~ts-~ts has no versions pending.",
ok = log(info, Message, [Realm, Name]),
halt(0);
{ok, Versions} ->
Print =
fun(Version) ->
PackageString = package_string({Realm, Name, Version}),
io:format("~ts~n", [PackageString])
end,
ok = lists:foreach(Print, Versions),
halt(0)
end.
-spec valid_package(package()) -> ok | no_return().
valid_package({Realm, Name}) ->
case {valid_lower0_9(Realm), valid_lower0_9(Name)} of
{true, true} ->
ok;
{false, true} ->
ok = log(error, "Invalid realm name: ~tp", [Realm]),
halt(1);
{true, false} ->
ok = log(error, "Invalid package name: ~tp", [Name]),
halt(1);
{false, false} ->
ok = log(error, "Invalid realm ~tp and package ~tp", [Realm, Name]),
halt(1)
end.
%%% Add realm
-spec add_realm(Path) -> no_return()
@ -621,35 +769,95 @@ add_package(PackageName) ->
%% This sysop-only command can add a package to a realm operated by the caller.
add_package(Realm, Name) ->
Socket =
case connect_auth(Realm) of
{ok, S} ->
S;
Error ->
M1 = "Connection failed to realm prime with ~160tp.",
ok = log(warning, M1, [Error]),
halt(1)
end,
Socket = connect_auth_or_die(Realm),
ok = send(Socket, {add_package, {Realm, Name}}),
receive
{tcp, Socket, Bin} ->
case binary_to_term(Bin, [safe]) of
ok ->
ok = log(info, "\"~ts-~ts\" added successfully.", [Realm, Name]),
halt(0);
{error, Reason} ->
M2 = "Operation failed. Server sends reason: ~160tp",
ok = log(error, M2, [Reason]),
halt(1)
end;
{tcp_closed, Socket} ->
halt_on_unexpected_close()
after 5000 ->
ok = log(warning, "Operation timed After submission to server."),
halt(1)
ok = recv_or_die(Socket),
ok = log(info, "\"~ts-~ts\" added successfully.", [Realm, Name]),
halt(0).
list_resigns(Realm) ->
Socket = connect_auth_or_die(Realm),
ok = send(Socket, {list_resigns, Realm}),
case recv_or_die(Socket) of
{ok, []} ->
Message = "No packages pending signature in ~tp.",
ok = log(info, Message, [Realm]),
halt(0);
{ok, PackageIDs} ->
Print =
fun(PackageID) ->
PackageString = package_string(PackageID),
io:format("~ts~n", [PackageString])
end,
ok = lists:foreach(Print, PackageIDs),
halt(0)
end.
add_packager(Package, UserName) ->
ok = log(info, "Would add ~ts to packagers for ~160tp now.", [UserName, Package]),
halt(0).
add_maintainer(Package, UserName) ->
ok = log(info, "Would add ~ts to maintainer for ~160tp now.", [UserName, Package]),
halt(0).
review(PackageID) ->
PackageString = package_string(PackageID),
ZrpPath = PackageString ++ ".zrp",
ok = log(info, "Saving to ~ts, unpacking to ./~ts/", [ZrpPath, PackageString]),
ok =
case {filelib:is_file(ZrpPath), filelib:is_file(PackageString)} of
{false, false} ->
ok;
{true, false} ->
ok = log(error, "~ts already exists. Aborting.", [ZrpPath]),
halt(1);
{false, true} ->
ok = log(error, "~ts already exists. Aborting.", [PackageString]),
halt(1);
{true true} ->
Message = "~ts and ~ts already exist. Aborting.",
ok = log(error, Message, [ZrpPath, PackageString]),
halt(1);
end,
Socket = connect_auth_or_die(),
ok = send(Socket, {review, PackageID}),
ok = receive_or_die(Socket),
{ok, ZrpBin} = recieve_or_die(Socket),
ok = file:write_file(ZrpPath, ZrpBin),
ok = disconnect(Socket),
{"zomp.meta", MetaBin} = erl_tar:extract(ZrpBin, [memory, {files, "zomp.meta"}]),
Meta = binary_to_term(MetaBin, [safe]),
approve(PackageID = {Realm, _, _}) ->
Socket = connect_auth_or_die(Realm),
ok = send(Socket, {approve, PackageID}),
ok = recv_or_die(Socket),
ok = log(info, "ok"),
halt(0).
reject(PackageID = {Realm, _, _}) ->
Socket = connect_auth_or_die(Realm),
ok = send(Socket, {reject, PackageID}),
ok = recv_or_die(Socket),
ok = log(info, "ok"),
halt(0).
resign(PackageID) ->
M = "Pull the indicated package",
ok = log(info, M, [PackageID]),
halt(0).
%%% Drop dependency
-spec drop_dep(package_id()) -> no_return().
@ -1057,6 +1265,43 @@ send(Socket, Message) ->
gen_tcp:send(Socket, Bin).
-spec recv_or_die(Socket) -> Result | no_return()
when Socket :: gen_tcp:socket(),
Result :: ok | {ok, term()}.
recv_or_die(Socket) ->
receive
{tcp, Socket, Bin} ->
case binary_to_term(Bin, [safe]) of
ok ->
ok;
{ok, Response} ->
{ok, Response};
{error, bad_realm} ->
ok = log(warning, "No such realm at the connected node.").
halt(1);
{error, bad_package} ->
ok = log(warning, "No such package.").
halt(1)
{error, bad_version} ->
ok = log(warning, "No such version."),
halt(1);
{error, not_in_queue} ->
ok = log(warning, "Version is not queued."),
halt(1);
{error, bad_message} ->
ok = log(error, "Oh noes! zx sent an illegal message!"),
halt(1)
end;
{tcp_closed, Socket} ->
ok = log(warning, "Lost connection to node unexpectedly."),
halt(1)
after 5000 ->
ok = log(warning, "Node timed out."),
halt(1)
end.
-spec halt_on_unexpected_close() -> no_return().
halt_on_unexpected_close() ->
@ -1169,7 +1414,7 @@ confirm_serial(Realm, Socket, Hosts) ->
Socket;
{ok, Current} when Current > Serial ->
ok = log(info, "Node's serial newer than ours. Storing."),
NewSerials = lists:keystore(Realm, 1, Current, {Realm, Serials}),
NewSerials = lists:keystore(Realm, 1, Serials, {Realm, Current}),
{ok, Host} = inet:peername(Socket),
ok = write_terms(hosts_cache_file(Realm), [Host | Hosts]),
ok = write_terms(SerialFile, NewSerials),
@ -1193,6 +1438,19 @@ confirm_serial(Realm, Socket, Hosts) ->
end.
-spec connect_auth_or_die(realm()) -> gen_tcp:socket() | no_return().
connect_auth_or_die(Realm) ->
case connect_auth(Realm) of
{ok, Socket} ->
Socket;
Error ->
M1 = "Connection failed to realm prime with ~160tp.",
ok = log(warning, M1, [Error]),
halt(1)
end.
-spec connect_auth(Realm) -> Result
when Realm :: realm(),
Result :: {ok, gen_tcp:socket()}