Thinking about fetch

This commit is contained in:
Craig Everett 2017-11-15 12:47:56 +09:00
parent 34656bef64
commit 3e3f72359a

164
zx
View File

@ -21,7 +21,7 @@
{realm = "otpr" :: name(), {realm = "otpr" :: name(),
name = none :: none | name(), name = none :: none | name(),
version = {z, z, z} :: version(), version = {z, z, z} :: version(),
type = app :: app | lib type = app :: app | lib,
deps = [] :: [package_id()], deps = [] :: [package_id()],
dir = none :: none | file:filename(), dir = none :: none | file:filename(),
socket = none :: none | gen_tcp:socket(), socket = none :: none | gen_tcp:socket(),
@ -139,49 +139,49 @@ start(_) ->
%% procedure the runtime will halt with an error message. %% procedure the runtime will halt with an error message.
run(Identifier, Args) -> run(Identifier, Args) ->
PackageID = {Realm, Name, Version} = package_id(Identifier), {Realm, Name, Version} = package_id(Identifier),
ok = file:set_cwd(zomp_dir()), ok = file:set_cwd(zomp_dir()),
PackageRoot = filename:join("lib", Identifier),
State = #s{realm = Realm, State = #s{realm = Realm,
name = Name, name = Name,
version = Version, version = Version},
dir = PackageRoot}, NextState = #s{version = Installed} = ensure_installed(State),
NextState = ensure_installed(State), PackageID = {Realm, Name, Installed},
Meta = read_meta(PackageRoot), Dir = filename:join("lib", package_string(PackageID)),
Meta = read_meta(Dir),
Deps = maps:get(deps, Meta), Deps = maps:get(deps, Meta),
NewState = ensure_deps(NextState#s{deps = Deps}), NewState = ensure_deps(NextState#s{dir = Dir, deps = Deps}),
execute(State). execute(NewState).
Required = [PackageID | Deps], % Required = [PackageID | Deps],
Needed = scrub(Required), % Needed = scrub(Required),
Host = {"localhost", 11411}, % Host = {"localhost", 11411},
Socket = connect(Host, user), % Socket = connect(Host, user),
ok = fetch(Socket, Needed), % ok = fetch(Socket, Needed),
ok = lists:foreach(fun install/1, Needed), % ok = lists:foreach(fun install/1, Needed),
ok = lists:foreach(fun build/1, Required), % ok = lists:foreach(fun build/1, Required),
ok = file:set_cwd(PackageRoot), % ok = file:set_cwd(PackageRoot),
case maps:get(type, Meta) of % case maps:get(type, Meta) of
app -> % app ->
true = register(zx, self()), % true = register(zx, self()),
ok = inets:start(), % ok = inets:start(),
ok = log(info, "Starting ~ts", [package_string(PackageID)]), % ok = log(info, "Starting ~ts", [package_string(PackageID)]),
PackageMod = list_to_atom(Name), % PackageMod = list_to_atom(Name),
{ok, Pid} = PackageMod:start(normal, Args), % {ok, Pid} = PackageMod:start(normal, Args),
Mon = monitor(process, Pid), % Mon = monitor(process, Pid),
Shell = spawn(shell, start, []), % Shell = spawn(shell, start, []),
ok = log(info, "Your shell is ~p, application is: ~p", [Shell, Pid]), % ok = log(info, "Your shell is ~p, application is: ~p", [Shell, Pid]),
State = #s{realm = Realm, % State = #s{realm = Realm,
name = Name, % name = Name,
version = Version, % version = Version,
pid = Pid, % pid = Pid,
mon = Mon}, % mon = Mon},
exec_wait(State); % exec_wait(State);
lib -> % lib ->
Message = "Lib ~ts is available on the system, but is not a standalone app.", % Message = "Lib ~ts is available on the system, but is not a standalone app.",
ok = log(info, Message, [package_string(PackageID)]), % ok = log(info, Message, [package_string(PackageID)]),
halt(0) % halt(0)
end. % end.
@ -335,16 +335,55 @@ latest_version({Realm, Name, Version}) ->
%% locating or acquiring the package fail, then exit with an error. %% locating or acquiring the package fail, then exit with an error.
ensure_installed(State = #s{realm = Realm, name = Name, version = Version}) -> ensure_installed(State = #s{realm = Realm, name = Name, version = Version}) ->
% If the startup style is to always check first, match for the exact version, case resolve_installed_version({Realm, Name, Version}) of
% If the startup style is to run a matching latest and then check exact -> State;
PackageString = package_string(PackageID), {ok, Installed} -> State#s{version = Installed};
PackageDir = filename:join("lib", PackageString), not_found -> ensure_dep(State)
case filelib:is_dir(PackageDir) of
true -> ok;
false -> ensure_dep(PackageID)
end. end.
-spec resolve_installed_version(PackageID) -> Result
when PackageID :: package_id(),
Result :: not_found
| exact
| {ok, Installed :: version()}.
%% @private
%% Resolve the provided PackageID to the latest matching installed package directory version
%% if one exists, returning a value that indicates whether an exact match was found (in the
%% case of a full version input), a version matching a partial version input was found, or no
%% match was found at all.
resolve_installed_version(PackageID) ->
PackageString = package_string(PackageID),
Pattern = PackageString ++ "*",
case filelib:wildcard(Pattern, "lib") of
[] ->
not_found;
[PackageString] ->
exact;
[Dir] ->
{_, _, Version} = package_id(Dir),
{ok, Versoin};
Dirs ->
Dir = lists:last(lists:sort(Dirs)),
{_, _, Version} = package_id(Dir),
{ok, Version}
end.
ensure_deps(State = #s{realm = Realm, deps = Deps, socket = MaybeSocket}) ->
case scrub(Deps) of
[] ->
State;
Needed ->
Sorted = lists:sort(Needed),
Partition =
fun(D = {R, _, _}, M) ->
maps:update_with(R, fun(Ds) -> [D | Ds] end, [D], M)
end,
Partitioned = lists:foldl(Partition, #{}, Needed),
-spec ensure_dep(package_id()) -> ok | no_return(). -spec ensure_dep(package_id()) -> ok | no_return().
%% @private %% @private
%% Given an PackageID as an argument, check whether its package file exists in the %% Given an PackageID as an argument, check whether its package file exists in the
@ -581,13 +620,13 @@ execute(State = #s{type = lib}) ->
Needed = scrub(Deps), % Needed = scrub(Deps),
Host = {"localhost", 11411}, % Host = {"localhost", 11411},
Socket = connect(Host, user), % Socket = connect(Host, user),
ok = fetch(Socket, Needed), % ok = fetch(Socket, Needed),
ok = lists:foreach(fun install/1, Needed), % ok = lists:foreach(fun install/1, Needed),
ok = lists:foreach(fun build/1, Deps), % ok = lists:foreach(fun build/1, Deps),
ok = file:set_cwd(ProjectRoot), % ok = file:set_cwd(ProjectRoot),
@ -751,7 +790,7 @@ submit(PackageFile) ->
{package_id, {Realm, Package, Version}} = lists:keyfind(package_id, 1, Meta), {package_id, {Realm, Package, Version}} = lists:keyfind(package_id, 1, Meta),
{sig, {KeyID = {Realm, KeyName}, _}} = lists:keyfind(sig, 1, Meta), {sig, {KeyID = {Realm, KeyName}, _}} = lists:keyfind(sig, 1, Meta),
true = ensure_keypair(KeyID), true = ensure_keypair(KeyID),
{ok, Socket = connect_auth(Realm, KeyName), {ok, Socket} = connect_auth(Realm, KeyName),
ok = send(Socket, {submit, {Realm, Package, Version}}), ok = send(Socket, {submit, {Realm, Package, Version}}),
ok = ok =
receive receive
@ -772,7 +811,7 @@ submit(PackageFile) ->
ok = ok =
receive receive
{tcp, Socket, Response2} -> {tcp, Socket, Response2} ->
log(info, "Response: ~tp", [Response2]); log(info, "Response: ~tp", [Response2])
after 5000 -> after 5000 ->
log(warning, "Server timed out!") log(warning, "Server timed out!")
end, end,
@ -1554,11 +1593,18 @@ build() ->
scrub([]) -> scrub([]) ->
[]; [];
scrub(Deps) -> scrub(Deps) ->
{ok, Names} = file:list_dir("lib"), lists:filter(fun(PackageID) -> not installed(PackageID) end, Deps).
Existing = lists:map(fun package_id/1, Names),
Need = ordsets:from_list(Deps),
Have = ordsets:from_list(Existing), -spec installed(package_id()) -> boolean().
ordsets:to_list(ordsets:subtract(Need, Have)). %% @private
%% True to its name, returns `true' if the package is installed (its directory found),
%% `false' otherwise.
installed(PackageID) ->
PackageString = package_string(PackageID),
PackageDir = filename:join("lib", PackageString),
filelib:is_dir(PackageDir).