This commit is contained in:
Craig Everett 2018-05-28 08:33:04 +09:00
parent c7b49eac69
commit 7e79c4393f
17 changed files with 478 additions and 161 deletions

4
zomp/etc/otpr/realm.conf Normal file
View File

@ -0,0 +1,4 @@
{realm, "otpr"}.
{prime, {"otpr.psychobitch.party",11311}}.
{sysop, "zxq9"}.
{key, "zxq9-root"}.

5
zomp/etc/sys.conf Normal file
View File

@ -0,0 +1,5 @@
{timeout, 5}.
{retry, 3}.
{maxconn, 5}.
{managed, []}.
{mirrors, []}.

1
zomp/etc/version.txt Normal file
View File

@ -0,0 +1 @@
0.1.0

Binary file not shown.

Binary file not shown.

Binary file not shown.

39
zomp/lib/otpr/zx/0.1.0/make_zx Executable file
View File

@ -0,0 +1,39 @@
#! /usr/bin/env escript
-mode(compile).
main(Args) ->
true = code:add_patha("ebin"),
up_to_date = make:all(),
ok = lists:foreach(fun dispatch/1, Args),
halt(0).
dispatch("edoc") ->
ok = edoc();
dispatch("dialyze") ->
ok = dialyze();
dispatch("test") ->
ok = test();
dispatch(Unknown) ->
ok = io:format("make_zx: Unknown directive: ~tp~n", [Unknown]),
halt(1).
edoc() ->
ok = io:format("EDOC: Writing docs...~n"),
edoc:application(zx, ".", []).
dialyze() ->
case dialyzer:run([{from, src_code}, {files_rec, ["./src"]}]) of
[] ->
io:format("Dialyzer found no errors and returned no warnings! Yay!~n");
Warnings ->
Messages = [dialyzer:format_warning(W) || W <- Warnings],
lists:foreach(fun io:format/1, Messages)
end.
test() ->
io:format("TEST: If I only had a brain.~n").

View File

@ -29,7 +29,7 @@
option/0, option/0,
host/0, host/0,
key_id/0, key_name/0, key_data/0, key_id/0, key_name/0, key_data/0,
user/0, username/0, lower0_9/0, label/0, user_id/0, user_name/0, lower0_9/0, label/0,
package_meta/0]). package_meta/0]).
-include("zx_logger.hrl"). -include("zx_logger.hrl").
@ -46,7 +46,6 @@
-type version() :: {Major :: non_neg_integer() | z, -type version() :: {Major :: non_neg_integer() | z,
Minor :: non_neg_integer() | z, Minor :: non_neg_integer() | z,
Patch :: non_neg_integer() | z}. Patch :: non_neg_integer() | z}.
-type identifier() :: realm() | package() | package_id().
-type option() :: {string(), term()}. -type option() :: {string(), term()}.
-type host() :: {string() | inet:ip_address(), inet:port_number()}. -type host() :: {string() | inet:ip_address(), inet:port_number()}.
-type key_id() :: {realm(), key_name()}. -type key_id() :: {realm(), key_name()}.
@ -1312,7 +1311,7 @@ connect_auth(Realm) ->
-spec connect_auth(Socket, Realm, User, KeyID, Key) -> Result -spec connect_auth(Socket, Realm, User, KeyID, Key) -> Result
when Socket :: gen_tcp:socket(), when Socket :: gen_tcp:socket(),
Realm :: realm(), Realm :: realm(),
User :: user(), User :: user_id(),
KeyID :: key_id(), KeyID :: key_id(),
Key :: term(), Key :: term(),
Result :: {ok, gen_tcp:socket()} Result :: {ok, gen_tcp:socket()}
@ -1393,7 +1392,7 @@ confirm_auth(Socket) ->
-spec prep_auth(Realm, RealmConf) -> {User, KeyID, Key} | no_return() -spec prep_auth(Realm, RealmConf) -> {User, KeyID, Key} | no_return()
when Realm :: realm(), when Realm :: realm(),
RealmConf :: [term()], RealmConf :: [term()],
User :: user(), User :: user_id(),
KeyID :: key_id(), KeyID :: key_id(),
Key :: term(). Key :: term().
%% @private %% @private
@ -1790,7 +1789,7 @@ dialyze() ->
%%% Create Realm & Sysop %%% Create Realm & Sysop
-spec create_user(realm(), username()) -> no_return(). -spec create_user(realm(), user_name()) -> no_return().
%% @private %% @private
%% Validate the realm and username provided, prompt the user to either select a keypair %% Validate the realm and username provided, prompt the user to either select a keypair
%% to use or generate a new one, and bundle a .zuser file for conveyance of the user %% to use or generate a new one, and bundle a .zuser file for conveyance of the user

View File

@ -0,0 +1,251 @@
%%% @doc
%%% zx_conf_sys: An interface to etc/sys.conf
%%%
%%% It may seem overkill to write an interface module for a config file that only tracks
%%% five things, but scattering this all around the project is just a bit too l33t for
%%% an infrastructure project like ZX.
%%%
%%% Each exported function that is named after an attribute has two versions, one of
%%% arity-1 and one of arity-2. The arity-1 version is a "getter", and the arity-2
%%% version is a "setter". Other functions deal with the data in a way that returns
%%% an answer and updates the state accordingly.
%%%
%%% Bad configuration data causes a reset to defaults so that the system can function.
%%% @end
-module(zx_conf_sys).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").
-export([load/0, save/1,
timeout/1, timeout/2,
retries/1, retries/2, retry/1, retries_left/1,
maxconn/1, maxconn/2,
managed/1, managed/2, add_managed/2, rem_managed/2,
mirrors/1, mirrors/2, add_mirror/2, rem_mirror/2, next_mirror/1,
reset/0]).
-export_type([data/0]).
-include("zx_logger.hrl").
%%% Type Definitions
-record(d,
{timeout = 5 :: pos_integer(),
retries = {0, 3} :: non_neg_integer(),
maxconn = 5 :: pos_integer(),
managed = sets:new() :: sets:set(zx:realm()),
mirrors = queue:new() :: queue:queue(zx:host())}).
-opaque data() :: #d{}.
%%% Interface functions
-spec load() -> data().
%% @doc
%% Read from etc/sys.conf and return a populated data() record if it exists, or
%% populate default values and write a new one if it does not. If a damaged sys.conf
%% is discovered it will be repaired. This function is side-effecty so should only
%% be called by zx_daemon and utility code.
load() ->
case file:consult(path()) of
{ok, List} ->
populate_data(List);
{error, Reason} ->
ok = log(error, "Load etc/sys.conf failed with: ~tp", [Reason]),
Data = #d{},
ok = save(Data),
Data
end.
populate_data(List) ->
Timeout =
case proplists:get_value(timeout, List, 5) of
V when is_integer(V) and V > 0 -> V;
_ -> 5
end,
Retry =
case proplists:get_value(retry, List, 3) of
V when is_integer(V) and V > 0 -> V;
_ -> 3
end,
MaxConn =
case proplists:get_value(maxconn, List, 5) of
V when is_integer(V) and V > 0 -> V;
_ -> 5
end,
Managed =
case proplists:get_value(managed, List, []) of
V when is_list(V) -> sets:from_list(V);
_ -> sets:new()
end,
Mirrors =
case proplists:get_value(mirrors, List, []) of
V when is_list(V) -> queue:from_list(V);
_ -> queue:new()
end,
#d{timeout = Timeout,
retries = Retries,
maxconn = MaxConn,
managed = Managed,
mirrors = Mirrors}.
-spec save(data()) -> ok.
%% @doc
%% Save the current etc/sys.conf to disk.
save(#d{timeout = Timeout,
retries = {_, Retries},
maxconn = MaxConn,
managed = Managed,
mirrors = Mirrors}) ->
Terms =
[{timeout, Timeout},
{retries, Retries},
{maxconn, MaxConn},
{managed, sets:to_list(Managed)},
{mirrors, queue:to_list(Mirrors)}],
ok = zx_lib:write_terms(path(), Terms),
log(info, "Wrote etc/sys.conf").
-spec timeout(data()) -> pos_integer().
%% @doc
%% Return the timeout value.
timeout(#d{timeout = Timeout}) ->
Timeout.
-spec timeout(Data, Value) -> NewData
when Data :: data(),
Value :: pos_integer(),
NewData :: data().
%% @doc
%% Set the timeout attribute to a new value.
timeout(Data, Value)
when is_integer(Value) and Value > 0 ->
Data#d{timeout = Value}.
-spec retries(data()) -> non_neg_integer().
%% @doc
%% Return the retries value.
retries(#d{retries = Retries}) ->
Retries.
-spec retries(Data, Value) -> NewData
when Data :: data(),
Value :: non_neg_integer(),
NewData :: data().
%% @doc
%% Set the retries attribute to a new value.
retries(Data = #d{retries = {Remaining, _}, Value) ->
when is_integer(Value) and Value >= 0 ->
Data#d{retries = {Remaining, Value}}.
-spec retry(Data) -> Result
when Data :: data(),
Result :: {ok, NewData}
| no_retries,
NewData :: data().
%% @doc
%% Tell the caller whether there are any more retries remaining or return `ok' and
%% update the state.
retry(#d{retries = {0, _}}) ->
no_retries;
retry(Data = #d{retries = {Remaining, Setting}}) ->
NewRemaining = Current - 1,
NewData = Data#d{retries = {NewRemaining, Setting}},
{ok, NewData}.
-spec retries_left(data()) -> non_neg_integer().
%% @doc
%% Return the number of retries remaining.
retries_left(#d{retries = {Remaining, _}}) ->
Remaining.
-spec maxconn(data()) -> pos_integer().
%% @doc
%% Return the value of maxconn.
maxconn(#d{maxconn = MaxConn}) ->
MaxConn.
-spec maxconn(Data, Value) -> NewData
when Data :: data(),
Value :: pos_integer(),
NewData :: data().
%% @doc
%% Set the value of maxconn.
maxconn(Data, Value)
when is_integer(Value) and Value > 0 ->
Data#d{maxconn = Value}.
-spec managed(data()) -> list(zx:realm()).
%% @doc
%% Return the list of realms managed by the current node.
managed(#d{managed = Managed}) ->
sets:to_list(Managed).
-spec managed(Data, List) -> NewData
when Data :: data(),
List :: [zx:realm()],
NewData :: data().
%% @doc
%% Reset the set of managed realms entirely.
%% The realms must be configured on the current realm at a minimum.
managed(Data, List) ->
Scrubbed = scrub_realms(List),
NewManaged = sets:from_list(Scrubbed),
Data#d{managed = NewManaged}.
scrub_realms(List) ->
%...
[].
-spec add_managed(Data, Realm) -> {ok,
when Data :: data(),
Realm :: zx:realm(),
NewData :: data().
%% @doc
%% Add a new realm to the list of managed realms. The new realm must be configured on
%% the current node.
add_managed(Data = #d{managed = Managed}, Realm) ->
case zx_lib:valid_lower0_9(Realm) of
-spec path() -> file:filename().
%% @private
%% Return the path to $ZOMP_DIR/etc/sys.conf.
path() ->
filename:join(zx_lib:path(etc), "sys.conf").

View File

@ -266,6 +266,7 @@ handle_message(Socket, Bin) ->
handle_request(Socket, Action) -> handle_request(Socket, Action) ->
ok = zx_net:send(Socket, Action), ok = zx_net:send(Socket, Action),
Response =
case element(1, Action) of case element(1, Action) of
list -> list ->
do_list(Action, Socket); do_list(Action, Socket);
@ -287,6 +288,27 @@ handle_request(Socket, Action) ->
handle_response(Socket, Response). handle_response(Socket, Response).
handle_fetch(_, _) -> {error, nyi}.
handle_query(_, _) -> {error, nyi}.
do_list(_, _) -> {error, nyi}.
do_latest(_, _) -> {error, nyi}.
do_fetch(_, _) -> {error, nyi}.
do_key(_, _) -> {error, nyi}.
do_pending(_, _) -> {error, nyi}.
do_packagers(_, _) -> {error, nyi}.
do_maintainers(_, _) -> {error, nyi}.
do_sysops(_, _) -> {error, nyi}.
handle_response(Socket, Command) -> handle_response(Socket, Command) ->
receive receive
@ -305,21 +327,21 @@ interpret_response(Socket, ping, Command) ->
handle_response(Socket, Command); handle_response(Socket, Command);
interpret_response(Socket, {sub, Channel, Message}, Command) -> interpret_response(Socket, {sub, Channel, Message}, Command) ->
ok = zx_daemon:notify(Channel, Message), ok = zx_daemon:notify(Channel, Message),
handle_response(Socket, Command); handle_response(Socket, Command).
interpret_response(Socket, {update, Message}, Command) -> %interpret_response(Socket, {update, Message}, Command) ->
interpret_response(Socket, Response, list) -> %interpret_response(Socket, Response, list) ->
interpret_response(Socket, Response, latest) -> %interpret_response(Socket, Response, latest) ->
interpret_response(Socket, Response, fetch) -> %interpret_response(Socket, Response, fetch) ->
interpret_response(Socket, Response, key) -> %interpret_response(Socket, Response, key) ->
interpret_response(Socket, Response, pending) -> %interpret_response(Socket, Response, pending) ->
interpret_response(Socket, Response, packagers) -> %interpret_response(Socket, Response, packagers) ->
interpret_response(Socket, Response, maintainers) -> %interpret_response(Socket, Response, maintainers) ->
interpret_response(Socket, Response, sysops) -> %interpret_response(Socket, Response, sysops) ->
%
%
%
case element(1, Action) of % case element(1, Action) of
end, % end,
-spec fetch(Socket, PackageID) -> Result -spec fetch(Socket, PackageID) -> Result

View File

@ -5,13 +5,13 @@
%%% %%%
%%% The daemon resides in the background once started and awaits query requests and %%% The daemon resides in the background once started and awaits query requests and
%%% subscriptions from other processes. The daemon is only capable of handling %%% subscriptions from other processes. The daemon is only capable of handling
%%% unprivileged (user) actions. %%% unprivileged ("leaf") actions.
%%% %%%
%%% %%%
%%% Discrete state and local abstract data types %%% Discrete state and local abstract data types
%%% %%%
%%% The daemon must keep track of requestors, subscribers, and zx_conn processes by %%% The daemon must keep track of requestors, subscribers, peers, and zx_conn processes
%%% using monitors. Because these various types of clients are found in different %%% by using monitors. Because these various types of clients are found in different
%%% structures the monitors are maintained in a data type called monitor_index(), %%% structures the monitors are maintained in a data type called monitor_index(),
%%% shortened to "mx" throughout the module. This structure is treated as an opaque %%% shortened to "mx" throughout the module. This structure is treated as an opaque
%%% data type and is handled by a set of functions defined toward the end of the module %%% data type and is handled by a set of functions defined toward the end of the module
@ -20,18 +20,23 @@
%%% Node connections (zx_conn processes) must also be tracked for status and realm %%% Node connections (zx_conn processes) must also be tracked for status and realm
%%% availability. This is done using a type called conn_index(), shortened to "cx" %%% availability. This is done using a type called conn_index(), shortened to "cx"
%%% throughout the module. conn_index() is treated as an abstract, opaque datatype %%% throughout the module. conn_index() is treated as an abstract, opaque datatype
%%% throughout the module, and is handled via a set of cx_*/N functions (after the %%% throughout the module and is handled via a set of cx_*/N functions (after the
%%% mx_*/N section). %%% mx_*/N section).
%%% %%%
%%% Do NOT directly access data within these structures, use (or write) an accessor %%% Do NOT directly access data within these structures, use (or write) an accessor
%%% function that does what you want. Accessor functions MUST be pure with the sole %%% function that does what you want. Accessor functions MUST be pure with the
%%% exception of the mx_* functions that create and destroy monitors. %%% exception of mx_add_monitor/3 and mx_del_monitor/3 that create and destroy
%%% monitors.
%%% %%%
%%% %%%
%%% Connection handling %%% Connection handling
%%% %%%
%%% The daemon is structured as a service manager in a service -> worker structure. %%% The daemon is structured as a service manager in a service -> worker structure.
%%% http://zxq9.com/archives/1311 %%% http://zxq9.com/archives/1311
%%% This allows it to abstract the servicing of tasks at a high level, making it
%%% unnecessary for other processes to talk directly to any zx_conn processes or care
%%% whether the current runtime is the host's zx proxy or a peer instance.
%%%
%%% It is in charge of the high-level task of servicing requested actions and returning %%% It is in charge of the high-level task of servicing requested actions and returning
%%% responses to callers as well as mapping successful connections to configured realms %%% responses to callers as well as mapping successful connections to configured realms
%%% and repairing failed connections to nodes that reduce availability of configured %%% and repairing failed connections to nodes that reduce availability of configured
@ -40,8 +45,9 @@
%%% When the zx_daemon is started it checks local configuration and cache files to %%% When the zx_daemon is started it checks local configuration and cache files to
%%% determine what realms must be available and what cached Zomp nodes it is aware of. %%% determine what realms must be available and what cached Zomp nodes it is aware of.
%%% It populates the CX (conn_index(), mentioned above) with realm config and host %%% It populates the CX (conn_index(), mentioned above) with realm config and host
%%% cache data, and then immediately initiates three connection attempts to cached %%% cache data, and then initiates a connection attempt to each configured prime node
%%% nodes for each realm configured if possible (see init_connections/0). %%% and up to maxconn connection attempts to cached nodes for each realm as well.
%%% (See init_connections/0).
%%% %%%
%%% Once connection attempts have been initiated the daemon waits in receive for %%% Once connection attempts have been initiated the daemon waits in receive for
%%% either a connection report (success or failure) or an action request from %%% either a connection report (success or failure) or an action request from
@ -83,6 +89,7 @@
%%% should not be cases where the work queue stalls on active requests. %%% should not be cases where the work queue stalls on active requests.
%%% %%%
%%% Requestors sending either download or realm query requests are given a reference %%% Requestors sending either download or realm query requests are given a reference
%%% (an integer, not an Erlang reference, as the message may cross node boundaries)
%%% to match on for receipt of their result messages or to be used to cancel the %%% to match on for receipt of their result messages or to be used to cancel the
%%% requested work (timeouts are handled by the caller, not by the daemon). %%% requested work (timeouts are handled by the caller, not by the daemon).
%%% %%%
@ -105,7 +112,7 @@
%%% within a host system. %%% within a host system.
%%% %%%
%%% When zx starts the daemon will attempt an exclusive write to a lock file called %%% When zx starts the daemon will attempt an exclusive write to a lock file called
%%% $ZOMP_HOME/zomp.lock using file:open(LockFile, [exclusive]), writing a system %%% $ZOMP_DIR/john.locke using file:open(LockFile, [exclusive]), writing a system
%%% timestamp. If the write succeeds then the daemon knows it is the master for the %%% timestamp. If the write succeeds then the daemon knows it is the master for the
%%% system and will begin initiating connections as described above as well as open a %%% system and will begin initiating connections as described above as well as open a
%%% local socket to listen for other zx instances which will need to proxy their own %%% local socket to listen for other zx instances which will need to proxy their own
@ -140,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/1, key/1, fetch_zsp/1, fetch_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]).
@ -165,6 +172,7 @@
{meta = none :: none | zx:package_meta(), {meta = none :: none | zx:package_meta(),
home = none :: none | file:filename(), home = none :: none | file:filename(),
argv = none :: none | [string()], argv = none :: none | [string()],
sys_conf = zx_conf_sys:load() :: zx_conf_sys:data(),
id = 0 :: id(), id = 0 :: id(),
actions = [] :: [request()], actions = [] :: [request()],
requests = maps:new() :: requests(), requests = maps:new() :: requests(),
@ -438,7 +446,7 @@ latest({Realm, Name, Version}) ->
request({latest, Realm, Name, Version}). request({latest, Realm, Name, Version}).
-spec fetch(PackageID) -> {ok, RequestID} -spec fetch_zsp(PackageID) -> {ok, RequestID}
when PackageID :: zx:package_id(), when PackageID :: zx:package_id(),
RequestID :: integer(). RequestID :: integer().
%% @doc %% @doc

View File

@ -14,7 +14,8 @@
-copyright("Craig Everett <zxq9@zxq9.com>"). -copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0"). -license("GPL-3.0").
-export([zomp_home/0, find_zomp_home/0, -export([zomp_dir/0, find_zomp_dir/0,
path/1, path/2, path/3,
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,
write_project_meta/1, write_project_meta/2, write_project_meta/1, write_project_meta/2,
@ -33,41 +34,92 @@
%%% Functions %%% Functions
zomp_home() -> -spec zomp_dir() -> file:filename().
case os:getenv("ZOMP_HOME") of %% @doc
%% Return the path to the Zomp/ZX installation directory.
zomp_dir() ->
case os:getenv("ZOMP_DIR") of
false -> false ->
ZompHome = find_zomp_home(), ZompDir = find_zomp_dir(),
true = os:putenv("ZOMP_HOME", ZompHome), true = os:putenv("ZOMP_DIR", ZompDir),
ZompHome; ZompDir;
ZompHome -> ZompDir ->
ZompHome ZompDir
end. end.
-spec find_zomp_home() -> file:filename(). -spec find_zomp_dir() -> file:filename().
%% @private %% @private
%% Check the host OS and return the absolute path to the zomp filesystem root. %% Check the host OS and return the absolute path to the zomp filesystem root.
find_zomp_home() -> find_zomp_dir() ->
case os:type() of case os:type() of
{unix, _} -> {unix, _} ->
Home = os:getenv("HOME"), Home = os:getenv("HOME"),
Dir = "zomp", Dir = "zomp",
filename:join(Home, Dir); filename:join(Home, Dir);
{win32, _} -> {win32, _} ->
Drive = os:getenv("HOMEDRIVE"), Home = os:getenv("LOCALAPPDATA"),
Path = os:getenv("HOMEPATH"),
Dir = "zomp", Dir = "zomp",
filename:join([Drive, Path, Dir]) filename:join(Home, Dir)
end. end.
-spec path(Type) -> Result
when Type :: etc
| var
| tmp
| log
| lib,
Result :: file:filename().
%% @doc
%% Return the top-level path of the given type in the Zomp/ZX system.
path(etc) -> filename:join(zomp_dir(), "etc");
path(var) -> filename:join(zomp_dir(), "var");
path(tmp) -> filename:join(zomp_dir(), "tmp");
path(log) -> filename:join(zomp_dir(), "log");
path(lib) -> filename:join(zomp_dir(), "lib").
-spec path(Type, Realm) -> Result
when Type :: etc
| var
| tmp
| log
| lib,
Realm :: zx:realm(),
Result :: file:filename().
%% @doc
%% Return the realm-level path of the given type in the Zomp/ZX system.
path(Type, Realm) ->
filename:join(path(Type), Realm).
-spec path(Type, Realm, Name) -> Result
when Type :: etc
| var
| tmp
| log
| lib,
Realm :: zx:realm(),
Name :: zx:name(),
Result :: file:filename().
%% @doc
%% Return the package-level path of the given type in the Zomp/ZX system.
path(Type, Realm, Name) ->
filename:join([path(Type), Realm, Name]).
-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.
hosts_cache_file(Realm) -> hosts_cache_file(Realm) ->
filename:join(zomp_home(), Realm ++ ".hosts"). filename:join(zomp_dir(), Realm ++ ".hosts").
-spec get_prime(Realm) -> Result -spec get_prime(Realm) -> Result
@ -99,7 +151,7 @@ get_prime(Realm) ->
%% the file. %% the file.
realm_meta(Realm) -> realm_meta(Realm) ->
RealmFile = filename:join(zomp_home(), Realm ++ ".realm"), RealmFile = filename:join(zomp_dir(), Realm ++ ".realm"),
file:consult(RealmFile). file:consult(RealmFile).
@ -139,7 +191,7 @@ read_project_meta(Dir) ->
read_package_meta({Realm, Name, Version}) -> read_package_meta({Realm, Name, Version}) ->
{ok, VersionString} = version_to_string(Version), {ok, VersionString} = version_to_string(Version),
Path = filename:join([zomp_home(), "lib", Realm, Name, VersionString]), Path = filename:join([zomp_dir(), "lib", Realm, Name, VersionString]),
read_project_meta(Path). read_project_meta(Path).
@ -449,7 +501,7 @@ package_dir({Realm, Name, Version = {X, Y, Z}})
when is_integer(X), is_integer(Y), is_integer(Z) -> when is_integer(X), is_integer(Y), is_integer(Z) ->
{ok, PackageDir} = package_string({Realm, Name}), {ok, PackageDir} = package_string({Realm, Name}),
{ok, VersionDir} = version_to_string(Version), {ok, VersionDir} = version_to_string(Version),
filename:join([zomp_home(), "lib", PackageDir, VersionDir]). filename:join([zomp_dir(), "lib", PackageDir, VersionDir]).
-spec package_dir(Prefix, Package) -> PackageDataDir -spec package_dir(Prefix, Package) -> PackageDataDir
@ -461,7 +513,7 @@ package_dir({Realm, Name, Version = {X, Y, Z}})
package_dir(Prefix, {Realm, Name}) -> package_dir(Prefix, {Realm, Name}) ->
PackageString = package_string({Realm, Name, {z, z, z}}), PackageString = package_string({Realm, Name, {z, z, z}}),
filename:join([zomp_home(), Prefix, PackageString]). filename:join([zomp_dir(), Prefix, PackageString]).
-spec namify_zrp(PackageID) -> ZrpFileName -spec namify_zrp(PackageID) -> ZrpFileName
@ -568,5 +620,5 @@ realm_conf(Realm) ->
%% Load the config for the given realm or halt with an error. %% Load the config for the given realm or halt with an error.
load_realm_conf(Realm) -> load_realm_conf(Realm) ->
Path = filename:join(zx_lib:zomp_home(), realm_conf(Realm)), Path = filename:join(zomp_dir(), realm_conf(Realm)),
file:consult(Path). file:consult(Path).

View File

@ -1,48 +0,0 @@
#! /usr/bin/env escript
-mode(compile).
main(Args) ->
ok = make(),
ok = lists:foreach(fun dispatch/1, Args),
halt(0).
dispatch("edoc") ->
ok = edoc();
dispatch("dialyze") ->
ok = dialyze();
dispatch("test") ->
ok = test();
dispatch(Unknown) ->
ok = io:format("zmake: Unknown directive: ~tp~n", [Unknown]),
halt(1).
make() ->
true = code:add_patha("ebin"),
up_to_date = make:all(),
halt(0).
edoc() ->
ok = io:format("EDOC: Writing docs...~n"),
ok = edoc:application(zomp, ".", []),
halt(0).
dialyze() ->
ok =
case dialyzer:run([{from, src_code}, {files_rec, ["./src"]}]) of
[] ->
io:format("Dialyzer found no errors and returned no warnings! Yay!~n");
Warnings ->
Messages = [dialyzer:format_warning(W) || W <- Warnings],
lists:foreach(fun io:format/1, Messages)
end,
halt(0).
test() ->
ok = io:format("TEST: If I only had a brain.~n"),
halt(0).

View File

@ -1,20 +0,0 @@
{realm,"otpr"}.
{revision,0}.
{prime,{"otpr.psychobitch.party",11311}}.
{sysops,[{{"otpr","zxq9"},["zxq9.1"],"zxq9@zxq9.com","Craig Everett"}]}.
{realm_keys,[{{"otpr","otpr.1.realm"},
realm,
{realm,"otpr"},
<<206,129,232,15,23,149,65,167,9,157,25,210,91,113,55,56,14,12,
153,218,37,83,148,3,89,208,61,43,95,89,51,228,245,78,115,52,15,
82,23,100,53,189,136,19,104,58,222,216,184,87,75,231,151,18,90,
243,115,160,244,32,232,71,57,95>>,
{{2018,1,10},{6,36,41}}}]}.
{package_keys,[{{"otpr","otpr.1.package"},
package,
{realm,"otpr"},
<<77,10,171,53,73,87,21,251,153,215,83,119,244,217,207,77,44,
210,177,77,46,86,52,232,16,64,23,109,214,94,207,140,12,145,
23,130,151,151,37,82,61,240,82,146,142,199,95,114,77,219,148,
200,140,85,128,77,110,142,179,137,169,188,223,192>>,
{{2018,1,10},{6,36,41}}}]}.

11
zomp/zx
View File

@ -1,13 +1,10 @@
#!/bin/sh #!/bin/sh
set -x
ZOMP_DIR="$HOME/zomp" ZOMP_DIR="$HOME/zomp"
ORIGIN="$(pwd)" VERSION=$(cat "$ZOMP_DIR/etc/version.txt")
VERSION="$(ls $ZOMP_DIR/lib/otpr/zx/ | sort --field-separator=. --reverse | head --lines=1)"
ZX_DIR="$ZOMP_DIR/lib/otpr/zx/$VERSION" ZX_DIR="$ZOMP_DIR/lib/otpr/zx/$VERSION"
cd "$ZX_DIR" pushd "$ZX_DIR"
./zmake ./make_zx
cd "$ZOMP_DIR" popd
erl -pa "$ZX_DIR/ebin" -run zx start $@ erl -pa "$ZX_DIR/ebin" -run zx start $@

9
zomp/zx.cmd Normal file
View File

@ -0,0 +1,9 @@
REM Prepare the environment for ZX and launch it
set ZOMP_DIR="%LOCALAPPDATA%\zomp"
set VERSION=<"%ZOMP_DIR%\etc\version.txt"
set ZX_DIR="%ZOMP_DIR%\lib\otpr\zx\%VERSION%"
pushd "%ZX_DIR%"
escript.exe make_zx
popd
erl.exe -pa "%ZX_DIR%/ebin" -run zx start "%*"

18
zx_dev
View File

@ -1,13 +1,11 @@
#!/bin/sh #!/bin/bash
set -x ZX_DEV_ROOT=$(dirname $BASH_SOURCE)
ZOMP_DIR="$ZX_DEV_ROOT/zomp"
VERSION=$(cat "$ZOMP_DIR/etc/version.txt")
ZX_DIR="$ZOMP_DIR/lib/otpr/zx/$VERSION"
ZOMP_DIR="$HOME/vcs/zx/zomp" pushd "$ZX_DIR"
ORIGIN="$(pwd)" ./make_zx
VERSION="$(ls $ZOMP_DIR/lib/otpr-zx/ | sort --field-separator=. --reverse | head --lines=1)" popd
ZX_DIR="$ZOMP_DIR/lib/otpr-zx/$VERSION"
cd "$ZX_DIR"
./zmake
cd "$ZOMP_DIR"
erl -pa "$ZX_DIR/ebin" -run zx start $@ erl -pa "$ZX_DIR/ebin" -run zx start $@