From 3e3f72359a616d8c2a620d2ea380448b67305d81 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 15 Nov 2017 12:47:56 +0900 Subject: [PATCH] Thinking about fetch --- zx | 164 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 105 insertions(+), 59 deletions(-) diff --git a/zx b/zx index 4573149..a66d838 100755 --- a/zx +++ b/zx @@ -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).