diff --git a/zomp/lib/otpr-zx/0.1.0/src/zx.erl b/zomp/lib/otpr-zx/0.1.0/src/zx.erl index f08d944..71332ec 100644 --- a/zomp/lib/otpr-zx/0.1.0/src/zx.erl +++ b/zomp/lib/otpr-zx/0.1.0/src/zx.erl @@ -82,16 +82,12 @@ do(["set", "version", VersionString]) -> do(["list", "realms"]) -> list_realms(); do(["list", "packages", Realm]) -> - ok = valid_realm(Realm), list_packages(Realm); do(["list", "versions", PackageName]) -> - Package = string_to_package(PackageName), - list_versions(Package); + list_versions(PackageName); do(["list", "pending", PackageName]) -> - Package = string_to_package(PackageName), - list_pending(Package); + list_pending(PackageName); do(["list", "resigns", Realm]) -> - ok = valid_realm(Realm), list_resigns(Realm); do(["add", "realm", RealmFile]) -> add_realm(RealmFile); @@ -321,10 +317,11 @@ execute(PackageID, Meta, Dir, RunArgs) -> -spec execute(Type, PackageID, Meta, Dir, RunArgs) -> no_return() - when Type :: app | lib, - Meta :: package_meta(), - Dir :: file:filename(), - RunArgs :: [string()]. + when Type :: app | lib, + PackageID :: package_id(), + Meta :: package_meta(), + Dir :: file:filename(), + RunArgs :: [string()]. %% @private %% Gets all the target application's ducks in a row and launches them, then enters %% the exec_wait/1 loop to wait for any queries from the application. @@ -337,10 +334,10 @@ execute(app, PackageID, Meta, Dir, RunArgs) -> ok = zx_daemon:pass_meta(Meta, Dir), ok = ensure_all_started(AppMod), ok = pass_argv(AppMod, RunArgs), - exec_wait(State); + log(info, "Launcher complete."); execute(lib, PackageID, _, _, _) -> Message = "Lib ~ts is available on the system, but is not a standalone app.", - PackageString = package_string(PackageID), + {ok, PackageString} = zx_lib:package_string(PackageID), ok = log(info, Message, [PackageString]), halt(0). @@ -447,7 +444,8 @@ assimilate(PackageFile) -> end, ok = file:set_cwd(CWD), Message = "~ts is now locally available.", - ok = log(info, Message, [package_string(PackageID)]), + {ok, PackageString} = zx_lib:package_string(PackageID), + ok = log(info, Message, [PackageString]), halt(0). @@ -486,7 +484,8 @@ set_dep({Realm, Name}, Version) -> Deps = maps:get(deps, Meta), case lists:member(PackageID, Deps) of true -> - ok = log(info, "~ts is already a dependency", [package_string(PackageID)]), + {ok, PackageString} = zx_lib:package_string(PackageID), + ok = log(info, "~ts is already a dependency", [PackageString]), halt(0); false -> set_dep(PackageID, Deps, Meta) @@ -509,12 +508,13 @@ set_dep(PackageID = {Realm, Name, NewVersion}, Deps, Meta) -> case lists:partition(ExistingPackageIDs, Deps) of {[{Realm, Name, OldVersion}], Rest} -> Message = "Updating dep ~ts to ~ts", - OldPackageString = package_string({Realm, Name, OldVersion}), - NewPackageString = package_string({Realm, Name, NewVersion}), - ok = log(info, Message, [OldPackageString, NewPackageString]), + {ok, OldPS} = zx_lib:package_string({Realm, Name, OldVersion}), + {ok, NewPS} = zx_lib:package_string({Realm, Name, NewVersion}), + ok = log(info, Message, [OldPS, NewPS]), [PackageID | Rest]; {[], Deps} -> - ok = log(info, "Adding dep ~ts", [package_string(PackageID)]), + {ok, PackageString} = zx_lib:package_string(PackageID), + ok = log(info, "Adding dep ~ts", [PackageString]), [PackageID | Deps] end, NewMeta = maps:put(deps, NewDeps, Meta), @@ -620,7 +620,7 @@ set_version(VersionString) -> Name :: name(), OldVersion :: version(), NewVersion :: version(), - OldMeta :: project_meta(). + OldMeta :: package_meta(). %% @private %% Update a project's `zomp.meta' file by either incrementing the indicated component, %% or setting the version number to the one specified in VersionString. @@ -676,27 +676,34 @@ list_packages(Realm) -> error_exit("Realm \"~ts\" is not configured.", ?LINE); {error, network} -> Message = "Network issues are preventing connection to the realm.", - error_exit(Message, ?LINE); + error_exit(Message, ?LINE) end. --spec list_versions(package()) -> no_return(). +-spec list_versions(PackageName :: string()) -> no_return(). %% @private %% List the available versions of the package indicated. The user enters a string-form %% package name (such as "otpr-zomp") and the return values will be full package strings %% of the form "otpr-zomp-1.2.3", one per line printed to stdout. -list_versions(Package) -> +list_versions(PackageName) -> + Package = {Realm, Name} = + case zx_lib:package_id(PackageName) of + {ok, {R, N, {z, z, z}}} -> + {R, N}; + {error, invalid_package_string} -> + error_exit("~tp is not a valid package name.", [PackageName], ?LINE) + end, ok = start(), case zx_daemon:list_versions(Package) of - {ok, []} - Message = "Package ~ts-~ts has no versions available.", - ok = log(info, Message, [Realm, Name]), + {ok, []} -> + Message = "Package ~ts has no versions available.", + ok = log(info, Message, [PackageName]), halt(0); {ok, Versions} -> Print = fun(Version) -> - PackageString = package_string({Realm, Name, Version}), + {ok, PackageString} = zx_lib:package_string({Realm, Name, Version}), io:format("~ts~n", [PackageString]) end, ok = lists:foreach(Print, Versions), @@ -711,23 +718,30 @@ list_versions(Package) -> end. --spec list_pending(package()) -> no_return(). +-spec list_pending(PackageName :: string()) -> no_return(). %% @private %% List the versions of a package that are pending review. The package name is input by %% the user as a string of the form "otpr-zomp" and the output is a list of full %% package IDs, printed one per line to stdout (like "otpr-zomp-3.2.2"). -list_pending(Package) -> +list_pending(PackageName) -> + Package = {Realm, Name} = + case zx_lib:package_id(PackageName) of + {ok, {R, N, {z, z, z}}} -> + {R, N}; + {error, invalid_package_string} -> + error_exit("~tp is not a valid package name.", [PackageName], ?LINE) + end, ok = start(), case zx_daemon:list_pending(Package) of {ok, []} -> - Message = "Package ~ts-~ts has no versions pending.", - ok = log(info, Message, [Realm, Name]), + Message = "Package ~ts has no versions pending.", + ok = log(info, Message, [PackageName]), halt(0); {ok, Versions} -> Print = fun(Version) -> - PackageString = package_string({Realm, Name, Version}), + {ok, PackageString} = zx_lib:package_string({Realm, Name, Version}), io:format("~ts~n", [PackageString]) end, ok = lists:foreach(Print, Versions), @@ -757,7 +771,7 @@ list_resigns(Realm) -> {ok, PackageIDs} -> Print = fun(PackageID) -> - PackageString = package_string(PackageID), + {ok, PackageString} = zx_lib:package_string(PackageID), io:format("~ts~n", [PackageString]) end, ok = lists:foreach(Print, PackageIDs), @@ -824,7 +838,7 @@ add_realm(Path, Data) -> add_package(PackageName) -> ok = file:set_cwd(zx_lib:zomp_home()), case zx_lib:package_id(PackageName) of - {ok, {Realm, Name, {z, z, z}} -> + {ok, {Realm, Name, {z, z, z}}} -> add_package(Realm, Name); _ -> error_exit("~tp is not a valid package name.", [PackageName], ?LINE) @@ -942,7 +956,7 @@ resign(PackageString) -> %% Remove the indicate dependency from the local project's zomp.meta record. drop_dep(PackageID) -> - PackageString = package_string(PackageID), + {ok, PackageString} = zx_lib:package_string(PackageID), {ok, Meta} = zx_lib:read_project_meta(), Deps = maps:get(deps, Meta), case lists:member(PackageID, Deps) of @@ -1138,7 +1152,7 @@ package(KeyID, TargetDir) -> {ok, Meta} = zx_lib:read_project_meta(TargetDir), PackageID = maps:get(package_id, Meta), true = element(1, PackageID) == element(1, KeyID), - PackageString = package_string(PackageID), + {ok, PackageString} = zx_lib:package_string(PackageID), ZrpFile = PackageString ++ ".zrp", TgzFile = PackageString ++ ".tgz", ok = halt_if_exists(ZrpFile), @@ -1302,7 +1316,8 @@ connect_auth(Socket, Realm, User, KeyID, Key) -> ok = binary_to_term(Bin, [safe]), confirm_auth(Socket, Realm, User, KeyID, Key); {tcp_closed, Socket} -> - halt_on_unexpected_close() + ok = log(warning, "Socket closed unexpectedly."), + halt(1) after 5000 -> ok = log(warning, "Host realm ~160tp prime timed out.", [Realm]), {error, auth_timeout} @@ -1340,7 +1355,8 @@ confirm_auth(Socket, Realm, User, KeyID, Key) -> {error, Reason} end; {tcp_closed, Socket} -> - halt_on_unexpected_close() + ok = log(warning, "Socket closed unexpectedly."), + halt(1) after 5000 -> ok = log(warning, "Host realm ~tp prime timed out.", [Realm]), {error, auth_timeout} @@ -1355,7 +1371,8 @@ confirm_auth(Socket) -> Other -> {error, Other} end; {tcp_closed, Socket} -> - halt_on_unexpected_close() + ok = log(warning, "Socket closed unexpectedly."), + halt(1) after 5000 -> {error, timeout} end. @@ -1670,7 +1687,7 @@ loadkey(Type, {Realm, KeyName}) -> P = filename:join([zx_lib:zomp_home(), "key", Realm, KeyDer]), {'RSAPrivateKey', P}; public -> - PubDer = KeyName ++ ".pub.der" + PubDer = KeyName ++ ".pub.der", P = filename:join([zx_lib:zomp_home(), "key", Realm, PubDer]), {'RSAPublicKey', P} end, @@ -1781,17 +1798,6 @@ create_user(Realm, Username) -> %% realm file to the user. create_realm() -> - ConfFile = filename:join(zx_lib:zomp_home(), "zomp.conf"), - case file:consult(ConfFile) of - {ok, ZompConf} -> create_realm(ZompConf); - {error, enoent} -> create_realm([]) - end. - - --spec create_realm(ZompConf) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}]. - -create_realm(ZompConf) -> Instructions = "~n" " Enter a name for your new realm.~n" @@ -1804,29 +1810,23 @@ create_realm(ZompConf) -> RealmFile = filename:join(zx_lib:zomp_home(), Realm ++ ".realm"), case filelib:is_regular(RealmFile) of false -> - create_realm(ZompConf, Realm); + create_realm(Realm); true -> ok = io:format("That realm already exists. Be more original.~n"), - create_realm(ZompConf) + create_realm() end; false -> ok = io:format("Bad realm name \"~ts\". Try again.~n", [Realm]), - create_realm(ZompConf) + create_realm() end. --spec create_realm(ZompConf, Realm) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(). +-spec create_realm(Realm) -> no_return() + when Realm :: realm(). -create_realm(ZompConf, Realm) -> - ExAddress = - case lists:keyfind(external_address, 1, ZompConf) of - false -> prompt_external_address(); - {external_address, none} -> prompt_external_address(); - {external_address, Current} -> prompt_external_address(Current) - end, - create_realm(ZompConf, Realm, ExAddress). +create_realm(Realm) -> + ExAddress = prompt_external_address(), + create_realm(Realm, ExAddress). -spec prompt_external_address() -> Result @@ -1844,26 +1844,6 @@ prompt_external_address() -> end. --spec prompt_external_address(Current) -> Result - when Current :: inet:hostname() | inet:ip_address(), - Result :: inet:hostname() | inet:ip_address(). - -prompt_external_address(Current) -> - XAString = - case inet:ntoa(Current) of - {error, einval} -> Current; - XAS -> XAS - end, - Message = - external_address_prompt() ++ - " [The current public address is: ~ts. Press to keep this address.]~n", - ok = io:format(Message, [XAString]), - case get_input() of - "" -> Current; - String -> parse_address(String) - end. - - -spec external_address_prompt() -> string(). external_address_prompt() -> @@ -1883,49 +1863,35 @@ parse_address(String) -> end. --spec create_realm(ZompConf, Realm, ExAddress) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), +-spec create_realm(Realm, ExAddress) -> no_return() + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(). -create_realm(ZompConf, Realm, ExAddress) -> - Current = - case lists:keyfind(external_port, 1, ZompConf) of - false -> 11311; - {external_port, none} -> 11311; - {external_port, P} -> P - end, +create_realm(Realm, ExAddress) -> Message = "~n" " Enter the public (external) port number at which this service should be " "available. (This might be different from the local port number if you are " "forwarding ports or have a complex network layout.)~n", ok = io:format(Message), - ExPort = prompt_port_number(Current), - create_realm(ZompConf, Realm, ExAddress, ExPort). + ExPort = prompt_port_number(11311), + create_realm(Realm, ExAddress, ExPort). --spec create_realm(ZompConf, Realm, ExAddress, ExPort) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), +-spec create_realm(Realm, ExAddress, ExPort) -> no_return() + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(), ExPort :: inet:port_number(). -create_realm(ZompConf, Realm, ExAddress, ExPort) -> - Current = - case lists:keyfind(internal_port, 1, ZompConf) of - false -> 11311; - {internal_port, none} -> 11311; - {internal_port, P} -> P - end, +create_realm(Realm, ExAddress, ExPort) -> Message = "~n" " Enter the local (internal/LAN) port number at which this service should be " "available. (This might be different from the public port visible from the " "internet if you are port forwarding or have a complex network layout.)~n", ok = io:format(Message), - InPort = prompt_port_number(Current), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort). + InPort = prompt_port_number(11311), + create_realm(Realm, ExAddress, ExPort, InPort). -spec prompt_port_number(Current) -> Result @@ -1957,14 +1923,13 @@ prompt_port_number(Current) -> end. --spec create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), +-spec create_realm(Realm, ExAddress, ExPort, InPort) -> no_return() + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(), ExPort :: inet:port_number(), InPort :: inet:port_number(). -create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) -> +create_realm(Realm, ExAddress, ExPort, InPort) -> Instructions = "~n" " Enter a username for the realm sysop.~n" @@ -1974,22 +1939,21 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) -> UserName = get_input(), case zx_lib:valid_lower0_9(UserName) of true -> - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName); + create_realm(Realm, ExAddress, ExPort, InPort, UserName); false -> ok = io:format("Bad username ~tp. Try again.~n", [UserName]), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort) + create_realm(Realm, ExAddress, ExPort, InPort) end. --spec create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), +-spec create_realm(Realm, ExAddress, ExPort, InPort, UserName) -> no_return() + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(), ExPort :: inet:port_number(), InPort :: inet:port_number(), UserName :: string(). -create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) -> +create_realm(Realm, ExAddress, ExPort, InPort, UserName) -> Instructions = "~n" " Enter an email address for the realm sysop.~n" @@ -2001,48 +1965,43 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) -> [User, Host] = string:lexemes(Email, "@"), case {zx_lib:valid_lower0_9(User), zx_lib:valid_label(Host)} of {true, true} -> - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email); + create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email); {false, true} -> Message = "The user part of the email address seems invalid. Try again.~n", ok = io:format(Message), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName); + create_realm(Realm, ExAddress, ExPort, InPort, UserName); {true, false} -> Message = "The host part of the email address seems invalid. Try again.~n", ok = io:format(Message), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName); + create_realm(Realm, ExAddress, ExPort, InPort, UserName); {false, false} -> Message = "This email address seems like its totally bonkers. Try again.~n", ok = io:format(Message), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName) + create_realm(Realm, ExAddress, ExPort, InPort, UserName) end. --spec create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) -> +-spec create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email) -> no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(), ExPort :: inet:port_number(), InPort :: inet:port_number(), UserName :: string(), Email :: string(). -create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) -> +create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email) -> Instructions = "~n" " Enter the real name (or whatever name people recognize) for the sysop.~n" " There are no rules for this one. Any valid UTF-8 printables are legal.~n", ok = io:format(Instructions), RealName = get_input(), - create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealName). + create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email, RealName). --spec create_realm(ZompConf, Realm, - ExAddress, ExPort, InPort, - UserName, Email, RealName) -> - no_return() - when ZompConf :: [{Key :: atom(), Value :: term()}], - Realm :: realm(), +-spec create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email, RealName) -> no_return() + when Realm :: realm(), ExAddress :: inet:hostname() | inet:ip_address(), ExPort :: inet:port_number(), InPort :: inet:port_number(), @@ -2050,7 +2009,7 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email) -> Email :: string(), RealName :: string(). -create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealName) -> +create_realm(Realm, ExAddress, ExPort, InPort, UserName, Email, RealName) -> ok = io:format("~nGenerating keys. This might take a while, so settle in...~n"), {ok, RealmKey, RealmPub} = generate_rsa({Realm, Realm ++ ".1.realm"}), {ok, PackageKey, PackagePub} = generate_rsa({Realm, Realm ++ ".1.package"}), @@ -2095,9 +2054,6 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealNa {external_port, ExPort}, {internal_port, InPort}], - RealmFN = Realm ++ ".realm", - RealmConf = filename:join(zx_lib:zomp_home(), RealmFN), - ok = zx_lib:write_terms(RealmConf, RealmSettings), {ok, CWD} = file:get_cwd(), {ok, TempDir} = mktemp_dir("zomp"), ok = file:set_cwd(TempDir), @@ -2109,22 +2065,21 @@ create_realm(ZompConf, Realm, ExAddress, ExPort, InPort, UserName, Email, RealNa {ok, _} = file:copy(K, filename:join(KeyDir, filename:basename(K))), ok end, - TarOpts = [compressed, {cwd, TempDir}], + PublicZRF = filename:join(CWD, Realm ++ ".zrf"), + RealmFN = Realm ++ ".realm", ok = zx_lib:write_terms(RealmFN, RealmSettings), ok = KeyCopy(PackagePub), ok = KeyCopy(RealmPub), - PublicZRF = filename:join(CWD, Realm ++ ".zrf"), - Files = filelib:wildcard("**"), - ok = erl_tar:create(PublicZRF, [RealmFN, "key"], TarOpts), + ok = erl_tar:create(PublicZRF, [RealmFN, "key"], [compressed]), + PrimeZRF = filename:join(CWD, Realm ++ ".zpf"), ok = KeyCopy(SysopPub), ok = zx_lib:write_terms("zomp.conf", ZompSettings), - PrimeZRF = filename:join(CWD, Realm ++ ".zpf"), - ok = erl_tar:create(PrimeZRF, [RealmFN, "zomp.conf", "key"], TarOpts), + ok = erl_tar:create(PrimeZRF, [RealmFN, "zomp.conf", "key"], [compressed]), - ok = file:set_cwd(zx_lib:zomp_home()), KeyBundle = filename:join(CWD, Realm ++ ".zkf"), + ok = lists:foreach(KeyCopy, [PackageKey, RealmKey, SysopKey]), ok = erl_tar:create(KeyBundle, [KeyDir], [compressed]), ok = file:set_cwd(CWD), @@ -2225,7 +2180,7 @@ create_sysop() -> %% - If this function crashes it will completely halt the system install(PackageID) -> - PackageString = package_string(PackageID), + {ok, PackageString} = zx_lib:package_string(PackageID), ok = log(info, "Installing ~ts", [PackageString]), ZrpFile = filename:join("zrp", zx_lib:namify_zrp(PackageID)), Files = extract_zrp_or_die(ZrpFile), @@ -2412,36 +2367,15 @@ rm_rf(Path) -> end. --spec ensure_zomp_home() -> ok. +-spec rm(file:filename()) -> ok | {error, file:posix()}. %% @private -%% Ensure the zomp home directory exists and is populated. -%% Every entry function should run this initially. +%% An omnibus delete helper. -ensure_zomp_home() -> - ZompDir = zx_lib:zomp_home(), - case filelib:is_dir(ZompDir) of - true -> ok; - false -> setup(ZompDir) - end. - - --spec setup(ZompDir :: file:filename()) -> ok. - -setup(ZompDir) -> - {ok, CWD} = file:get_cwd(), - ok = force_dir(ZompDir), - ok = file:set_cwd(ZompDir), - SubDirs = ["tmp", "key", "var", "lib", "zrp", "etc"], - ok = lists:foreach(fun file:make_dir/1, SubDirs), - ok = setup_otpr(), - ok = log(info, "Zomp userland directory initialized."), - file:set_cwd(CWD). - - --spec setup_otpr() -> ok. - -setup_otpr() -> - log(info, "Here should pull otpr.0.zrf and install it..."). +rm(Path) -> + case filelib:is_dir(Path) of + true -> file:del_dir(Path); + false -> file:delete(Path) +end. -spec ensure_package_dirs(package_id()) -> ok.