Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote branch 'upstream/master' into cleanup-option-parsing-old

Conflicts:
	src/agner.erl
  • Loading branch information...
commit 4b9a49d3c471e7bb94fa183fe4931ca74af820aa 2 parents ebbf23e + 8f39b8e
@jlouis authored
View
5 README.md
@@ -59,12 +59,15 @@ This section introduces the terminology of Agner:
Command invocation
------------------
- agner list [-d/--descriptions]
+ agner list [-d/--descriptions] [-p/--properties PROPERTY1,PROPERTY2]
Will list all agner-packages. With the `-d` or `--descriptions`
option, it will also print out the descriptions of the packages, for
easy grepping to find relevant packages.
+If `-p` or `--properties` with a comma-separated list of properties is specified, they will be also
+included into each listing (when present).
+
agner spec PACKAGE [-v/--version package_version] [-b/--browser]
[-h/--homepage]
View
2  include/agner_spec.hrl
@@ -8,6 +8,7 @@
-type agner_spec_property_name() :: {name, string()}.
-type agner_spec_property_description() :: {description, string()}.
+-type agner_spec_property_keywords() :: {keywords, list(string())}.
-type agner_spec_property_authors() :: {authors, list(string())}.
-type agner_spec_property_homepage() :: {homepage, string()}.
-type agner_spec_property_rebar_compatible() :: {rebar_compatible, boolean()}.
@@ -24,6 +25,7 @@
-type agner_spec_property() :: agner_spec_property_name() |
agner_spec_property_description() |
+ agner_spec_property_keywords() |
agner_spec_property_authors() |
agner_spec_property_homepage() |
agner_spec_property_rebar_compatible() |
View
151 src/agner.erl
@@ -13,160 +13,13 @@ start() ->
application:start(agner).
stop() ->
- error_logger:delete_report_handler(error_logger_tty_h),
application:stop(agner),
inets:stop(),
ssl:stop().
-arg_proplist() ->
- [{"spec",
- {spec,
- "Output the specification of a package",
- [
- {package, undefined, undefined, string, "Package name"},
- {browser, $b, "browser", boolean, "Show specification in the browser"},
- {homepage, $h, "homepage", boolean, "Show package homepage in the browser"},
- {version, $v, "version", {string, "@master"}, "Version"}
- ]}},
- {"versions",
- {versions,
- "Show the avilable releases and flavours of a package",
- [
- {package, undefined, undefined, string, "Package name"}
- ]}},
- {"list",
- {list,
- "List packages on stdout",
- [
- {descriptions, $d, "descriptions", {boolean, false}, "Show package descriptions"}
- ]}},
- {"fetch",
- {fetch,
- "Download a package",
- [
- {package, undefined, undefined, string, "Package name"},
- {directory, undefined, undefined, string, "Directory to check package out to"},
- {version, $v, "version", {string, "@master"}, "Version"}
- ]}},
- {"verify",
- {verify,
- "Verify the integrity of a .agner configuration file",
- [
- {spec, undefined, undefined, {string, "agner.config"}, "Specification file (agner.config by default)"}
- ]}}].
-
-command_descriptions() ->
- [{Cmd, Desc} || {Cmd, {_Atom, Desc, _Opts}} <- arg_proplist()].
-
-parse_args([Arg|Args]) ->
- case proplists:get_value(Arg, arg_proplist()) of
- undefined -> no_parse;
- {A, _Desc, OptSpec} -> {arg, A, Args, OptSpec}
- end;
-parse_args(_) -> no_parse.
-
-usage() ->
- OptSpec = [
- {command, undefined, undefined, string, "Command to be executed (e.g. spec)"}
- ],
- getopt:usage(OptSpec, "agner", "[options ...]"),
- io:format("Valid commands are:~n", []),
- [io:format(" ~-10s ~s~n", [Cmd, Desc]) || {Cmd, Desc} <- command_descriptions()].
-
main(Args) ->
- case parse_args(Args) of
- {arg, Command, ExtraArgs, OptSpec} ->
- start(),
- {ok, {Opts, _}} = getopt:parse(OptSpec, ExtraArgs),
- handle_command(Command, Opts),
- stop();
- no_parse ->
- usage()
- end.
-
-handle_command(spec, Opts) ->
- case proplists:get_value(package, Opts) of
- undefined ->
- io:format("ERROR: Package name required.~n");
- Package ->
- Version = proplists:get_value(version, Opts),
- case proplists:get_value(browser, Opts) of
- true ->
- agner_utils:launch_browser(spec_url(Package, Version));
- _ ->
- ignore
- end,
- Spec = spec(Package,Version),
- case proplists:get_value(homepage, Opts) of
- true ->
- agner_utils:launch_browser(proplists:get_value(homepage, Spec, "http://google.com/?q=" ++ Package));
- _ ->
- ignore
- end,
- io:format("~p~n",[Spec])
- end;
-
-handle_command(versions, Opts) ->
- case proplists:get_value(package, Opts) of
- undefined ->
- io:format("ERROR: Package name required.~n");
- Package ->
- io:format("~s",[plists:map(fun (Version) ->
- io_lib:format("~s~n",[agner_spec:version_to_list(Version)])
- end,
- versions(Package))])
- end;
-
-handle_command(list, Opts) ->
- ShowDescriptions = proplists:get_value(descriptions, Opts),
- io:format("~s",[lists:usort(plists:map(fun (Name) ->
- case ShowDescriptions of
- true ->
- io_lib:format("~-40s ~s~n",[Name, proplists:get_value(description, spec(Name))]);
- false ->
- io_lib:format("~s~n",[Name])
- end
- end,index()))
- ]);
-
-handle_command(fetch, Opts) ->
- case proplists:get_value(package, Opts) of
- undefined ->
- io:format("ERROR: Package name required.~n");
- Package ->
- Version = proplists:get_value(version, Opts),
- io:format("~p~n",[fetch(Package,Version,
- proplists:get_value(directory, Opts, Package))]),
- case proplists:get_value(caveats, spec(Package, Version)) of
- undefined ->
- ignore;
- Caveats when is_list(Caveats) ->
- io:format("=== CAVEATS ===~n~n~s~n~n",[Caveats])
- end
- end;
-
-handle_command(verify, Opts) ->
- SpecFile = proplists:get_value(spec, Opts),
- case file:consult(SpecFile) of
- {error, Reason} ->
- io:format("ERROR: Can't read ~s: ~p~n",[SpecFile, Reason]);
- {ok, Spec} ->
- URL = proplists:get_value(url, Spec),
- TmpFile = temp_name(),
- case (catch agner_download:fetch(URL,TmpFile)) of
- ok ->
- io:format("~nPASSED~n");
- {'EXIT', {Reason, _}} ->
- io:format("~nEROR: Can't fetch ~p: ~p~n",[URL, Reason]);
- {error, Reason} ->
- io:format("~nEROR: Can't fetch ~p: ~p~n",[URL, Reason])
- end,
- os:cmd("rm -rf " ++ TmpFile)
- end.
-
-temp_name() ->
- %% Yes, the temp_name function lives in the test_server, go figure!
- test_server:temp_name("/tmp/agner").
+ agner_main:main(Args).
+
%%%===================================================================
%%% API
View
181 src/agner_main.erl
@@ -0,0 +1,181 @@
+%% -*- Mode: Erlang; tab-width: 4 -*-
+-module(agner_main).
+-export([main/1]).
+
+start() ->
+ agner:start().
+
+stop() ->
+ error_logger:delete_report_handler(error_logger_tty_h),
+ agner:stop().
+
+arg_proplist() ->
+ [{"spec",
+ {spec,
+ "Output the specification of a package",
+ [
+ {package, undefined, undefined, string, "Package name"},
+ {browser, $b, "browser", boolean, "Show specification in the browser"},
+ {homepage, $h, "homepage", boolean, "Show package homepage in the browser"},
+ {version, $v, "version", {string, "@master"}, "Version"}
+ ]}},
+ {"versions",
+ {versions,
+ "Show the avilable releases and flavours of a package",
+ [
+ {package, undefined, undefined, string, "Package name"}
+ ]}},
+ {"list",
+ {list,
+ "List packages on stdout",
+ [
+ {descriptions, $d, "descriptions", {boolean, false}, "Show package descriptions"},
+ {properties, $p, "properties", string, "Comma-separated list of properties to show"}
+ ]}},
+ {"fetch",
+ {fetch,
+ "Download a package",
+ [
+ {package, undefined, undefined, string, "Package name"},
+ {directory, undefined, undefined, string, "Directory to check package out to"},
+ {version, $v, "version", {string, "@master"}, "Version"}
+ ]}},
+ {"verify",
+ {verify,
+ "Verify the integrity of a .agner configuration file",
+ [
+ {spec, undefined, undefined, {string, "agner.config"}, "Specification file (agner.config by default)"}
+ ]}}].
+
+command_descriptions() ->
+ [{Cmd, Desc} || {Cmd, {_Atom, Desc, _Opts}} <- arg_proplist()].
+
+parse_args([Arg|Args]) ->
+ case proplists:get_value(Arg, arg_proplist()) of
+ undefined -> no_parse;
+ {A, _Desc, OptSpec} -> {arg, A, Args, OptSpec}
+ end;
+parse_args(_) -> no_parse.
+
+usage() ->
+ OptSpec = [
+ {command, undefined, undefined, string, "Command to be executed (e.g. spec)"}
+ ],
+ getopt:usage(OptSpec, "agner", "[options ...]"),
+ io:format("Valid commands are:~n", []),
+ [io:format(" ~-10s ~s~n", [Cmd, Desc]) || {Cmd, Desc} <- command_descriptions()].
+
+main(Args) ->
+ case parse_args(Args) of
+ {arg, Command, ExtraArgs, OptSpec} ->
+ start(),
+ {ok, {Opts, _}} = getopt:parse(OptSpec, ExtraArgs),
+ handle_command(Command, Opts),
+ stop();
+ no_parse ->
+ usage()
+ end.
+
+handle_command(spec, Opts) ->
+ case proplists:get_value(package, Opts) of
+ undefined ->
+ io:format("ERROR: Package name required.~n");
+ Package ->
+ Version = proplists:get_value(version, Opts),
+ case proplists:get_value(browser, Opts) of
+ true ->
+ agner_utils:launch_browser(agner:spec_url(Package, Version));
+ _ ->
+ ignore
+ end,
+ Spec = agner:spec(Package,Version),
+ case proplists:get_value(homepage, Opts) of
+ true ->
+ agner_utils:launch_browser(proplists:get_value(homepage, Spec, "http://google.com/?q=" ++ Package));
+ _ ->
+ ignore
+ end,
+ io:format("~p~n",[Spec])
+ end;
+
+handle_command(versions, Opts) ->
+ case proplists:get_value(package, Opts) of
+ undefined ->
+ io:format("ERROR: Package name required.~n");
+ Package ->
+ io:format("~s",[plists:map(fun (Version) ->
+ io_lib:format("~s~n",[agner_spec:version_to_list(Version)])
+ end,
+ agner:versions(Package))])
+ end;
+
+handle_command(list, Opts) ->
+ ShowDescriptions = proplists:get_value(descriptions, Opts),
+ Properties = lists:map(fun list_to_atom/1, string:tokens(proplists:get_value(properties, Opts,""),",")),
+ io:format("~s",[lists:usort(plists:map(fun (Name) ->
+ Spec = agner:spec(Name),
+ Result0 = case ShowDescriptions of
+ true ->
+ io_lib:format("~-40s ~s",[Name, proplists:get_value(description, Spec)]);
+ false ->
+ io_lib:format("~s",[Name])
+ end,
+ Result = case Properties of
+ [] ->
+ Result0;
+ [_|_] ->
+ [Result0|lists:map(fun (Prop) ->
+ case lists:keyfind(Prop, 1, Spec) of
+ false ->
+ [];
+ T ->
+ Val = list_to_tuple(tl(tuple_to_list(T))),
+ io_lib:format(" | ~s: ~p",[Prop,
+ Val])
+ end
+ end, Properties)]
+ end,
+ Result ++ [$\n]
+ end,agner:index()))
+ ]);
+
+handle_command(fetch, Opts) ->
+ case proplists:get_value(package, Opts) of
+ undefined ->
+ io:format("ERROR: Package name required.~n");
+ Package ->
+ Version = proplists:get_value(version, Opts),
+ io:format("~p~n",[agner:fetch(Package,Version,
+ proplists:get_value(directory, Opts, Package))]),
+ case proplists:get_value(caveats, agner:spec(Package, Version)) of
+ undefined ->
+ ignore;
+ Caveats when is_list(Caveats) ->
+ io:format("=== CAVEATS ===~n~n~s~n~n",[Caveats])
+ end
+ end;
+
+handle_command(verify, Opts) ->
+ SpecFile = proplists:get_value(spec, Opts),
+ case file:consult(SpecFile) of
+ {error, Reason} ->
+ io:format("ERROR: Can't read ~s: ~p~n",[SpecFile, Reason]);
+ {ok, Spec} ->
+ URL = proplists:get_value(url, Spec),
+ TmpFile = temp_name(),
+ case (catch agner_download:fetch(URL,TmpFile)) of
+ ok ->
+ io:format("~nPASSED~n");
+ {'EXIT', {Reason, _}} ->
+ io:format("~nEROR: Can't fetch ~p: ~p~n",[URL, Reason]);
+ {error, Reason} ->
+ io:format("~nEROR: Can't fetch ~p: ~p~n",[URL, Reason])
+ end,
+ os:cmd("rm -rf " ++ TmpFile)
+ end.
+
+temp_name() ->
+ %% Yes, the temp_name function lives in the test_server, go figure!
+ test_server:temp_name("/tmp/agner").
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.