diff --git a/zx b/zx index c01203e..46c2555 100755 --- a/zx +++ b/zx @@ -32,7 +32,7 @@ -type state() :: #s{}. %-type serial() :: pos_integer(). -type package_id() :: {realm(), name(), version()}. -%-type package() :: {realm(), name()}. +-type package() :: {realm(), name()}. -type realm() :: lower0_9(). -type name() :: lower0_9(). -type version() :: {Major :: non_neg_integer() | z, @@ -306,9 +306,20 @@ ensure_installed(PackageID = {Realm, Name, Version}) -> end. +-spec ensure_installed(Realm, Name, Version) -> Result + when Realm :: realm(), + Name :: name(), + Version :: version(), + Result :: exact + | {ok, version()} + | not_found. +%% @private +%% Fetch and install the latest compatible version of the given package ID, whether +%% the version indicator is complete, partial or blank. + ensure_installed(Realm, Name, Version) -> Socket = connect_user(Realm), - case query_latest(Socket, {Realm, Name, Version}) of + case query_latest(Socket, {Realm, Name, Version}) of {ok, LatestVersion} -> LatestID = {Realm, Name, LatestVersion}, ok = ensure_dep(Socket, LatestID), @@ -329,6 +340,18 @@ ensure_installed(Realm, Name, Version) -> end. +-spec query_latest(Socket, Object) -> Result + when Socket :: gen_tcp:socket(), + Object :: package() | package_id(), + Result :: {ok, version()} + | {error, Reason}, + Reason :: bad_realm + | bad_package + | bad_version. +%% @private +%% Queries the connected zomp node for the latest version of a package or package +%% version (complete or incomplete version number). + query_latest(Socket, {Realm, Name}) -> ok = send(Socket, {latest, Realm, Name}), receive @@ -848,7 +871,7 @@ connect_user(Realm) -> connect_user(Realm, []) -> {Host, Port} = get_prime(Realm), - ok = log(info, "Realm host at ~ts:~tp", [inet:ntoa(Host), Port]), + ok = log(info, "Trying prime at ~ts:~tp", [inet:ntoa(Host), Port]), case gen_tcp:connect(Host, Port, connect_options(), 5000) of {ok, Socket} -> confirm_user(Realm, Socket, []); @@ -857,6 +880,7 @@ connect_user(Realm, []) -> halt(0) end; connect_user(Realm, Hosts = [Node = {Host, Port} | Rest]) -> + ok = log(info, "Trying node at ~ts:~tp", [inet:ntoa(Host), Port]), case gen_tcp:connect(Host, Port, connect_options(), 5000) of {ok, Socket} -> confirm_user(Realm, Socket, Hosts); @@ -1105,10 +1129,13 @@ realm_meta(Realm) -> prompt_keygen() -> Message = - " Enter a name for your new keys.~n" + "~n Enter a name for your new keys.~n~n" " Valid names must start with a lower-case letter, and can include~n" " only lower-case letters, numbers, and periods, but no series of~n" - " consecutive periods.~n", + " consecutive periods. (That is: [a-z0-9\\.])~n~n" + " To designate the key as realm-specific, enter the realm name and~n" + " key name separated by a space.~n~n" + " Example: some.realm my.key~n", ok = io:format(Message), Input = string:trim(io:get_line("(^C to quit): ")), {Realm, KeyName} = @@ -1136,10 +1163,8 @@ keygen() -> ok = file:set_cwd(zomp_dir()), KeyID = prompt_keygen(), case generate_rsa(KeyID) of - ok -> - halt(0); - Error -> - error_exit("keygen failed with ~tp", [Error], ?FILE, ?LINE) + ok -> halt(0); + Error -> error_exit("keygen failed with ~tp", [Error], ?FILE, ?LINE) end. @@ -1733,10 +1758,12 @@ package_id(String) -> true = valid_lower0_9(Name), Version = string_to_version(VersionString), {Realm, Name, Version}; - [Realm, Name] -> - true = valid_lower0_9(Realm), - true = valid_lower0_9(Name), - {Realm, Name, {z, z, z}}; + [A, B] -> + true = valid_lower0_9(A), + case valid_lower0_9(B) of + true -> {A, B, {z, z, z}}; + false -> {"otpr", A, string_to_version(B)} + end; [Name] -> true = valid_lower0_9(Name), {"otpr", Name, {z, z, z}}