commit
ede481f140
@ -99,6 +99,10 @@ do(["init", "app", PackageString]) ->
|
|||||||
do(["init", "lib", PackageString]) ->
|
do(["init", "lib", PackageString]) ->
|
||||||
ok = compatibility_check([unix]),
|
ok = compatibility_check([unix]),
|
||||||
done(zx_local:initialize(lib, PackageString));
|
done(zx_local:initialize(lib, PackageString));
|
||||||
|
do(["list", "deps"]) ->
|
||||||
|
done(zx_local:list_deps());
|
||||||
|
do(["list", "deps", PackageString]) ->
|
||||||
|
done(zx_local:list_deps(PackageString));
|
||||||
do(["install", PackageFile]) ->
|
do(["install", PackageFile]) ->
|
||||||
done(zx_local:assimilate(PackageFile));
|
done(zx_local:assimilate(PackageFile));
|
||||||
do(["set", "dep", PackageString]) ->
|
do(["set", "dep", PackageString]) ->
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
-copyright("Craig Everett <zxq9@zxq9.com>").
|
-copyright("Craig Everett <zxq9@zxq9.com>").
|
||||||
-license("GPL-3.0").
|
-license("GPL-3.0").
|
||||||
|
|
||||||
-export([ensure_keypair/1, have_key/2, keypath/2,
|
-export([ensure_keypair/1, have_key/2, path/2,
|
||||||
prompt_keygen/0, generate_rsa/1,
|
prompt_keygen/0, generate_rsa/1,
|
||||||
load/2, verify/3]).
|
load/2, verify/3]).
|
||||||
|
|
||||||
@ -51,19 +51,19 @@ ensure_keypair(KeyID = {Realm, KeyName}) ->
|
|||||||
%% Determine whether the indicated key is present.
|
%% Determine whether the indicated key is present.
|
||||||
|
|
||||||
have_key(Type, KeyID) ->
|
have_key(Type, KeyID) ->
|
||||||
filelib:is_regular(keypath(Type, KeyID)).
|
filelib:is_regular(path(Type, KeyID)).
|
||||||
|
|
||||||
|
|
||||||
-spec keypath(Type, KeyID) -> Path
|
-spec path(Type, KeyID) -> Path
|
||||||
when Type :: public | private,
|
when Type :: public | private,
|
||||||
KeyID :: zx:key_id(),
|
KeyID :: zx:key_id(),
|
||||||
Path :: file:filename().
|
Path :: file:filename().
|
||||||
%% @private
|
%% @private
|
||||||
%% Given KeyID, return the path to the key type indicated.
|
%% Given KeyID, return the path to the key type indicated.
|
||||||
|
|
||||||
keypath(public, {Realm, KeyName}) ->
|
path(public, {Realm, KeyName}) ->
|
||||||
filename:join(zx_lib:path(key, Realm), KeyName ++ ".pub.der");
|
filename:join(zx_lib:path(key, Realm), KeyName ++ ".pub.der");
|
||||||
keypath(private, {Realm, KeyName}) ->
|
path(private, {Realm, KeyName}) ->
|
||||||
filename:join(zx_lib:path(key, Realm), KeyName ++ ".key.der").
|
filename:join(zx_lib:path(key, Realm), KeyName ++ ".key.der").
|
||||||
|
|
||||||
|
|
||||||
@ -116,8 +116,8 @@ prompt_keygen() ->
|
|||||||
|
|
||||||
generate_rsa(KeyID = {Realm, KeyName}) ->
|
generate_rsa(KeyID = {Realm, KeyName}) ->
|
||||||
PemFile = filename:join(zx_lib:path(key, Realm), KeyName ++ ".pub.pem"),
|
PemFile = filename:join(zx_lib:path(key, Realm), KeyName ++ ".pub.pem"),
|
||||||
KeyFile = keypath(private, KeyID),
|
KeyFile = path(private, KeyID),
|
||||||
PubFile = keypath(public, KeyID),
|
PubFile = path(public, KeyID),
|
||||||
ok = lists:foreach(fun zx_lib:halt_if_exists/1, [PemFile, KeyFile, PubFile]),
|
ok = lists:foreach(fun zx_lib:halt_if_exists/1, [PemFile, KeyFile, PubFile]),
|
||||||
ok = log(info, "Generating ~p and ~p. Please be patient...", [KeyFile, PubFile]),
|
ok = log(info, "Generating ~p and ~p. Please be patient...", [KeyFile, PubFile]),
|
||||||
ok = gen_p_key(KeyFile),
|
ok = gen_p_key(KeyFile),
|
||||||
@ -234,7 +234,7 @@ load(Type, KeyID) ->
|
|||||||
private -> 'RSAPrivateKey';
|
private -> 'RSAPrivateKey';
|
||||||
public -> 'RSAPublicKey'
|
public -> 'RSAPublicKey'
|
||||||
end,
|
end,
|
||||||
Path = keypath(Type, KeyID),
|
Path = path(Type, KeyID),
|
||||||
ok = log(info, "Loading key from file ~ts", [Path]),
|
ok = log(info, "Loading key from file ~ts", [Path]),
|
||||||
case file:read_file(Path) of
|
case file:read_file(Path) of
|
||||||
{ok, Bin} -> {ok, public_key:der_decode(DerType, Bin)};
|
{ok, Bin} -> {ok, public_key:der_decode(DerType, Bin)};
|
||||||
|
|||||||
@ -786,7 +786,8 @@ rm(Path) ->
|
|||||||
|
|
||||||
b_to_t(Binary) ->
|
b_to_t(Binary) ->
|
||||||
try
|
try
|
||||||
binary_to_term(Binary)
|
Term = binary_to_term(Binary),
|
||||||
|
{ok, Term}
|
||||||
catch
|
catch
|
||||||
error:badarg -> error
|
error:badarg -> error
|
||||||
end.
|
end.
|
||||||
|
|||||||
@ -10,9 +10,9 @@
|
|||||||
-copyright("Craig Everett <zxq9@zxq9.com>").
|
-copyright("Craig Everett <zxq9@zxq9.com>").
|
||||||
-license("GPL-3.0").
|
-license("GPL-3.0").
|
||||||
|
|
||||||
-export([initialize/2, assimilate/1, set_dep/1, set_version/1,
|
-export([initialize/2, assimilate/1, set_version/1,
|
||||||
list_realms/0, list_packages/1, list_versions/1,
|
list_realms/0, list_packages/1, list_versions/1,
|
||||||
drop_dep/1, verup/1, package/1,
|
set_dep/1, list_deps/0, list_deps/1, drop_dep/1, verup/1, package/1,
|
||||||
add_realm/1, drop_realm/1,
|
add_realm/1, drop_realm/1,
|
||||||
takeover/1, abdicate/1,
|
takeover/1, abdicate/1,
|
||||||
create_plt/0, dialyze/0,
|
create_plt/0, dialyze/0,
|
||||||
@ -105,6 +105,15 @@ initialize(Type, PackageID, Prefix, AppStart) ->
|
|||||||
{appmod, AppStart}],
|
{appmod, AppStart}],
|
||||||
Meta = maps:from_list(MetaList),
|
Meta = maps:from_list(MetaList),
|
||||||
ok = zx_lib:write_project_meta(Meta),
|
ok = zx_lib:write_project_meta(Meta),
|
||||||
|
ok =
|
||||||
|
case filelib:is_regular("Emakefile") of
|
||||||
|
true ->
|
||||||
|
ok;
|
||||||
|
false ->
|
||||||
|
EM = [{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]},
|
||||||
|
{"test/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}],
|
||||||
|
zx_lib:write_terms("Emakefile", EM)
|
||||||
|
end,
|
||||||
{ok, PackageString} = zx_lib:package_string(PackageID),
|
{ok, PackageString} = zx_lib:package_string(PackageID),
|
||||||
ok = log(info, "Project ~tp initialized.", [PackageString]),
|
ok = log(info, "Project ~tp initialized.", [PackageString]),
|
||||||
Message =
|
Message =
|
||||||
@ -277,65 +286,6 @@ assimilate2(CWD, PackageID) ->
|
|||||||
log(info, Message, [PackageString]).
|
log(info, Message, [PackageString]).
|
||||||
|
|
||||||
|
|
||||||
-spec set_dep(Identifier :: string()) -> zx:outcome().
|
|
||||||
%% @private
|
|
||||||
%% Set a specific dependency in the current project. If the project currently has a
|
|
||||||
%% dependency on the same package then the version of that dependency is updated to
|
|
||||||
%% reflect that in the PackageString argument. The AppString is permitted to be
|
|
||||||
%% incomplete. Incomplete elements of the VersionString (if included) will default to
|
|
||||||
%% the latest version available at the indicated level.
|
|
||||||
|
|
||||||
set_dep(Identifier) ->
|
|
||||||
{ok, {Realm, Name, FuzzyVersion}} = zx_lib:package_id(Identifier),
|
|
||||||
case FuzzyVersion of
|
|
||||||
{X, Y, Z} when is_integer(X), is_integer(Y), is_integer(Z) ->
|
|
||||||
set_dep({Realm, Name}, {X, Y, Z});
|
|
||||||
_ ->
|
|
||||||
{error, "Incompelte version tuple.", 22}
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec set_dep(zx:package(), zx:version()) -> ok.
|
|
||||||
|
|
||||||
set_dep({Realm, Name}, Version) ->
|
|
||||||
PackageID = {Realm, Name, Version},
|
|
||||||
{ok, Meta} = zx_lib:read_project_meta(),
|
|
||||||
Deps = maps:get(deps, Meta),
|
|
||||||
case lists:member(PackageID, Deps) of
|
|
||||||
true -> ok;
|
|
||||||
false -> set_dep(PackageID, Deps, Meta)
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
-spec set_dep(PackageID, Deps, Meta) -> ok
|
|
||||||
when PackageID :: zx:package_id(),
|
|
||||||
Deps :: [zx:package_id()],
|
|
||||||
Meta :: [term()].
|
|
||||||
%% @private
|
|
||||||
%% Given the PackageID, list of Deps and the current contents of the project Meta, add
|
|
||||||
%% or update Deps to include (or update) Deps to reflect a dependency on PackageID, if
|
|
||||||
%% such a dependency is not already present. Then write the project meta back to its
|
|
||||||
%% file and exit.
|
|
||||||
|
|
||||||
set_dep(PackageID = {Realm, Name, NewVersion}, Deps, Meta) ->
|
|
||||||
ExistingPackageIDs = fun({R, N, _}) -> {R, N} == {Realm, Name} end,
|
|
||||||
NewDeps =
|
|
||||||
case lists:partition(ExistingPackageIDs, Deps) of
|
|
||||||
{[{Realm, Name, OldVersion}], Rest} ->
|
|
||||||
Message = "Updating dep ~ts to ~ts",
|
|
||||||
{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, PackageString} = zx_lib:package_string(PackageID),
|
|
||||||
ok = log(info, "Adding dep ~ts", [PackageString]),
|
|
||||||
[PackageID | Deps]
|
|
||||||
end,
|
|
||||||
NewMeta = maps:put(deps, NewDeps, Meta),
|
|
||||||
zx_lib:write_project_meta(NewMeta).
|
|
||||||
|
|
||||||
|
|
||||||
-spec set_version(VersionString) -> zx:outcome()
|
-spec set_version(VersionString) -> zx:outcome()
|
||||||
when VersionString :: string().
|
when VersionString :: string().
|
||||||
%% @private
|
%% @private
|
||||||
@ -464,7 +414,7 @@ add_realm(Path) ->
|
|||||||
{ok, Data} ->
|
{ok, Data} ->
|
||||||
Digest = crypto:hash(sha512, Data),
|
Digest = crypto:hash(sha512, Data),
|
||||||
Text = integer_to_list(binary:decode_unsigned(Digest, big), 16),
|
Text = integer_to_list(binary:decode_unsigned(Digest, big), 16),
|
||||||
ok = log(info, "SHA512 of ~ts: ~ts", [Path, Text]),
|
ok = log(info, "SHA-512 of ~ts: ~ts", [Path, Text]),
|
||||||
add_realm2(Data);
|
add_realm2(Data);
|
||||||
{error, enoent} ->
|
{error, enoent} ->
|
||||||
{error, "Realm bundle (.zrf) does not exist.", 2};
|
{error, "Realm bundle (.zrf) does not exist.", 2};
|
||||||
@ -482,9 +432,9 @@ add_realm2(Data) ->
|
|||||||
Realm = maps:get(realm, RealmConf),
|
Realm = maps:get(realm, RealmConf),
|
||||||
ok = make_realm_dirs(Realm),
|
ok = make_realm_dirs(Realm),
|
||||||
ConfPath = zx_lib:realm_conf(Realm),
|
ConfPath = zx_lib:realm_conf(Realm),
|
||||||
zx_lib:write_terms(ConfPath, maps:to_list(RealmConf)),
|
ok = zx_lib:write_terms(ConfPath, maps:to_list(RealmConf)),
|
||||||
KeyName = maps:get(key, RealmConf),
|
KeyName = maps:get(key, RealmConf),
|
||||||
KeyPath = zx_lib:keypath(public, {Realm, KeyName}),
|
KeyPath = zx_key:path(public, {Realm, KeyName}),
|
||||||
ok = file:write_file(KeyPath, KeyDER),
|
ok = file:write_file(KeyPath, KeyDER),
|
||||||
log(info, "Added realm ~tp.", [Realm]);
|
log(info, "Added realm ~tp.", [Realm]);
|
||||||
error ->
|
error ->
|
||||||
@ -492,6 +442,103 @@ add_realm2(Data) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec set_dep(PackageString :: string()) -> zx:outcome().
|
||||||
|
%% @private
|
||||||
|
%% Set a dependency in the current project. If the project currently has a dependency
|
||||||
|
%% on the same package then the version of that dependency is updated to reflect that
|
||||||
|
%% in the PackageString argument.
|
||||||
|
|
||||||
|
set_dep(PackageString) ->
|
||||||
|
case zx_lib:package_id(PackageString) of
|
||||||
|
{ok, {_, _, {_, _, z}}} ->
|
||||||
|
Message =
|
||||||
|
"Incomplete version tuple. Dependencies must be fully specified.",
|
||||||
|
{error, Message, 22};
|
||||||
|
{ok, PackageID} ->
|
||||||
|
set_dep2(PackageID);
|
||||||
|
{error, invalid_package_string} ->
|
||||||
|
{error, "Invalid package string", 22}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec set_dep2(zx:package_id()) -> ok.
|
||||||
|
|
||||||
|
set_dep2(PackageID) ->
|
||||||
|
{ok, Meta} = zx_lib:read_project_meta(),
|
||||||
|
Deps = maps:get(deps, Meta),
|
||||||
|
case lists:member(PackageID, Deps) of
|
||||||
|
true -> ok;
|
||||||
|
false -> set_dep(PackageID, Deps, Meta)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec set_dep(PackageID, Deps, Meta) -> ok
|
||||||
|
when PackageID :: zx:package_id(),
|
||||||
|
Deps :: [zx:package_id()],
|
||||||
|
Meta :: [term()].
|
||||||
|
%% @private
|
||||||
|
%% Given the PackageID, list of Deps and the current contents of the project Meta, add
|
||||||
|
%% or update Deps to include (or update) Deps to reflect a dependency on PackageID, if
|
||||||
|
%% such a dependency is not already present. Then write the project meta back to its
|
||||||
|
%% file and exit.
|
||||||
|
|
||||||
|
set_dep(PackageID = {Realm, Name, NewVersion}, Deps, Meta) ->
|
||||||
|
ExistingPackageIDs = fun({R, N, _}) -> {R, N} == {Realm, Name} end,
|
||||||
|
NewDeps =
|
||||||
|
case lists:partition(ExistingPackageIDs, Deps) of
|
||||||
|
{[{Realm, Name, OldVersion}], Rest} ->
|
||||||
|
Message = "Updating dep ~ts to ~ts",
|
||||||
|
{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, PackageString} = zx_lib:package_string(PackageID),
|
||||||
|
ok = log(info, "Adding dep ~ts", [PackageString]),
|
||||||
|
[PackageID | Deps]
|
||||||
|
end,
|
||||||
|
NewMeta = maps:put(deps, NewDeps, Meta),
|
||||||
|
zx_lib:write_project_meta(NewMeta).
|
||||||
|
|
||||||
|
|
||||||
|
-spec list_deps() -> zx:outcome().
|
||||||
|
%% @private
|
||||||
|
%% List deps in the current (local) project directory.
|
||||||
|
%% This is very different from list_deps/1, which makes a remote query to a Zomp
|
||||||
|
%% realm to discover deps for potentially unknown or locally uncached packages.
|
||||||
|
|
||||||
|
list_deps() ->
|
||||||
|
case zx_lib:read_project_meta() of
|
||||||
|
{ok, Meta} ->
|
||||||
|
Deps = maps:get(deps, Meta),
|
||||||
|
Print =
|
||||||
|
fun(P) ->
|
||||||
|
{ok, PackageString} = zx_lib:package_string(P),
|
||||||
|
io:format("~ts~n", [PackageString])
|
||||||
|
end,
|
||||||
|
lists:foreach(Print, Deps);
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec list_deps(zx:package_id()) -> zx:outcome().
|
||||||
|
%% @private
|
||||||
|
%% List deps for the specified package. This quite often requires a query to a Zomp
|
||||||
|
%% realm over the network, but not if the referenced package happens to be cached
|
||||||
|
%% locally.
|
||||||
|
|
||||||
|
list_deps(PackageString) ->
|
||||||
|
case zx_lib:package_id(PackageString) of
|
||||||
|
{ok, {_, _, {_, _, z}}} ->
|
||||||
|
{error, "Packages must be fully specified; no partial versions.", 22};
|
||||||
|
{ok, PackageID} ->
|
||||||
|
log(info, "Phooey! list_deps(~tp) isn't yet implemented!", [PackageID]);
|
||||||
|
{error, invalid_package_string} ->
|
||||||
|
{error, "Invalid package string.", 22}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec drop_dep(zx:package_id()) -> ok.
|
-spec drop_dep(zx:package_id()) -> ok.
|
||||||
%% @private
|
%% @private
|
||||||
%% Remove the indicate dependency from the local project's zomp.meta record.
|
%% Remove the indicate dependency from the local project's zomp.meta record.
|
||||||
@ -1050,7 +1097,7 @@ create_realmfile(Realm, Dir) ->
|
|||||||
{ok, RealmConf} = zx_lib:load_realm_conf(Realm),
|
{ok, RealmConf} = zx_lib:load_realm_conf(Realm),
|
||||||
ok = log(info, "Realm found, creating realm file..."),
|
ok = log(info, "Realm found, creating realm file..."),
|
||||||
KeyName = maps:get(key, RealmConf),
|
KeyName = maps:get(key, RealmConf),
|
||||||
PubKeyPath = zx_key:keypath(public, {Realm, KeyName}),
|
PubKeyPath = zx_key:path(public, {Realm, KeyName}),
|
||||||
{ok, PubDER} = file:read_file(PubKeyPath),
|
{ok, PubDER} = file:read_file(PubKeyPath),
|
||||||
Blob = term_to_binary({RealmConf, PubDER}),
|
Blob = term_to_binary({RealmConf, PubDER}),
|
||||||
ZRF = filename:join(Dir, Realm ++ ".zrf"),
|
ZRF = filename:join(Dir, Realm ++ ".zrf"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user