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(),
name = none :: none | name(),
version = {z, z, z} :: version(),
type = app :: app | lib
type = app :: app | lib,
deps = [] :: [package_id()],
dir = none :: none | file:filename(),
socket = none :: none | gen_tcp:socket(),
@ -139,49 +139,49 @@ start(_) ->
%% procedure the runtime will halt with an error message.
run(Identifier, Args) ->
PackageID = {Realm, Name, Version} = package_id(Identifier),
{Realm, Name, Version} = package_id(Identifier),
ok = file:set_cwd(zomp_dir()),
PackageRoot = filename:join("lib", Identifier),
State = #s{realm = Realm,
name = Name,
version = Version,
dir = PackageRoot},
NextState = ensure_installed(State),
Meta = read_meta(PackageRoot),
version = Version},
NextState = #s{version = Installed} = ensure_installed(State),
PackageID = {Realm, Name, Installed},
Dir = filename:join("lib", package_string(PackageID)),
Meta = read_meta(Dir),
Deps = maps:get(deps, Meta),
NewState = ensure_deps(NextState#s{deps = Deps}),
execute(State).
NewState = ensure_deps(NextState#s{dir = Dir, deps = Deps}),
execute(NewState).
Required = [PackageID | Deps],
Needed = scrub(Required),
Host = {"localhost", 11411},
Socket = connect(Host, user),
ok = fetch(Socket, Needed),
ok = lists:foreach(fun install/1, Needed),
ok = lists:foreach(fun build/1, Required),
ok = file:set_cwd(PackageRoot),
case maps:get(type, Meta) of
app ->
true = register(zx, self()),
ok = inets:start(),
ok = log(info, "Starting ~ts", [package_string(PackageID)]),
PackageMod = list_to_atom(Name),
{ok, Pid} = PackageMod:start(normal, Args),
Mon = monitor(process, Pid),
Shell = spawn(shell, start, []),
ok = log(info, "Your shell is ~p, application is: ~p", [Shell, Pid]),
State = #s{realm = Realm,
name = Name,
version = Version,
pid = Pid,
mon = Mon},
exec_wait(State);
lib ->
Message = "Lib ~ts is available on the system, but is not a standalone app.",
ok = log(info, Message, [package_string(PackageID)]),
halt(0)
end.
% Required = [PackageID | Deps],
% Needed = scrub(Required),
% Host = {"localhost", 11411},
% Socket = connect(Host, user),
% ok = fetch(Socket, Needed),
% ok = lists:foreach(fun install/1, Needed),
% ok = lists:foreach(fun build/1, Required),
% ok = file:set_cwd(PackageRoot),
% case maps:get(type, Meta) of
% app ->
% true = register(zx, self()),
% ok = inets:start(),
% ok = log(info, "Starting ~ts", [package_string(PackageID)]),
% PackageMod = list_to_atom(Name),
% {ok, Pid} = PackageMod:start(normal, Args),
% Mon = monitor(process, Pid),
% Shell = spawn(shell, start, []),
% ok = log(info, "Your shell is ~p, application is: ~p", [Shell, Pid]),
% State = #s{realm = Realm,
% name = Name,
% version = Version,
% pid = Pid,
% mon = Mon},
% exec_wait(State);
% lib ->
% Message = "Lib ~ts is available on the system, but is not a standalone app.",
% ok = log(info, Message, [package_string(PackageID)]),
% halt(0)
% end.
@ -335,16 +335,55 @@ latest_version({Realm, Name, Version}) ->
%% locating or acquiring the package fail, then exit with an error.
ensure_installed(State = #s{realm = Realm, name = Name, version = Version}) ->
% If the startup style is to always check first, match for the exact version,
% If the startup style is to run a matching latest and then check
PackageString = package_string(PackageID),
PackageDir = filename:join("lib", PackageString),
case filelib:is_dir(PackageDir) of
true -> ok;
false -> ensure_dep(PackageID)
case resolve_installed_version({Realm, Name, Version}) of
exact -> State;
{ok, Installed} -> State#s{version = Installed};
not_found -> ensure_dep(State)
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().
%% @private
%% 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),
Host = {"localhost", 11411},
Socket = connect(Host, user),
ok = fetch(Socket, Needed),
ok = lists:foreach(fun install/1, Needed),
ok = lists:foreach(fun build/1, Deps),
ok = file:set_cwd(ProjectRoot),
% Needed = scrub(Deps),
% Host = {"localhost", 11411},
% Socket = connect(Host, user),
% ok = fetch(Socket, Needed),
% ok = lists:foreach(fun install/1, Needed),
% ok = lists:foreach(fun build/1, Deps),
% ok = file:set_cwd(ProjectRoot),
@ -751,7 +790,7 @@ submit(PackageFile) ->
{package_id, {Realm, Package, Version}} = lists:keyfind(package_id, 1, Meta),
{sig, {KeyID = {Realm, KeyName}, _}} = lists:keyfind(sig, 1, Meta),
true = ensure_keypair(KeyID),
{ok, Socket = connect_auth(Realm, KeyName),
{ok, Socket} = connect_auth(Realm, KeyName),
ok = send(Socket, {submit, {Realm, Package, Version}}),
ok =
receive
@ -772,7 +811,7 @@ submit(PackageFile) ->
ok =
receive
{tcp, Socket, Response2} ->
log(info, "Response: ~tp", [Response2]);
log(info, "Response: ~tp", [Response2])
after 5000 ->
log(warning, "Server timed out!")
end,
@ -1554,11 +1593,18 @@ build() ->
scrub([]) ->
[];
scrub(Deps) ->
{ok, Names} = file:list_dir("lib"),
Existing = lists:map(fun package_id/1, Names),
Need = ordsets:from_list(Deps),
Have = ordsets:from_list(Existing),
ordsets:to_list(ordsets:subtract(Need, Have)).
lists:filter(fun(PackageID) -> not installed(PackageID) end, Deps).
-spec installed(package_id()) -> boolean().
%% @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).