diff options
Diffstat (limited to 'lib/stdlib/doc/src/argparse.xml')
-rw-r--r-- | lib/stdlib/doc/src/argparse.xml | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/lib/stdlib/doc/src/argparse.xml b/lib/stdlib/doc/src/argparse.xml new file mode 100644 index 0000000000..20e1f3a721 --- /dev/null +++ b/lib/stdlib/doc/src/argparse.xml @@ -0,0 +1,739 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<!-- %ExternalCopyright% --> + +<erlref> + <header> + <copyright> + <year>2020</year><year>2023</year> + <holder>Maxim Fedorov</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>argparse</title> + <prepared>maximfca@gmail.com</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>argparse.xml</file> + </header> + <module since="OTP 26.0">argparse</module> + <modulesummary>Command line arguments parser.</modulesummary> + <description> + + <p>This module implements command line parser. Parser operates with + <em>commands</em> and <em>arguments</em> represented as a tree. Commands + are branches, and arguments are leaves of the tree. Parser always starts with the + root command, named after <c>progname</c> (the name of the program which started Erlang). + </p> + + <p> + A <seetype marker="#command"><c>command specification</c></seetype> may contain handler + definition for each command, and a number argument specifications. When parser is + successful, <c>argparse</c> calls the matching handler, passing arguments extracted + from the command line. Arguments can be positional (occupying specific position in + the command line), and optional, residing anywhere but prefixed with a specified + character. + </p> + + <p> + <c>argparse</c> automatically generates help and usage messages. It will also issue + errors when users give the program invalid arguments. + </p> + + </description> + + <section> + <title>Quick start</title> + + <p><c>argparse</c> is designed to work with <seecom marker="erts:escript"><c>escript</c></seecom>. + The example below is a fully functioning Erlang program accepting two command line + arguments and printing their product.</p> + + <code> +#!/usr/bin/env escript + +main(Args) -> + argparse:run(Args, cli(), #{progname => mul}). + +cli() -> + #{ + arguments => [ + #{name => left, type => integer}, + #{name => right, type => integer} + ], + handler => + fun (#{left := Left, right := Right}) -> + io:format("~b~n", [Left * Right]) + end + }. + </code> + + <p>Running this script with no arguments results in an error, accompanied + by the usage information.</p> + + <p> + The <c>cli</c> function defines a single command with embedded handler + accepting a map. Keys of the map are argument names as defined by + the <c>argument</c> field of the command, <c>left</c> and <c>right</c> + in the example. Values are taken from the command line, and converted + into integers, as requested by the type specification. Both arguments + in the example above are required (and therefore defined as positional). + </p> + </section> + + <section> + <title>Command hierarchy</title> + + <p>A command may contain nested commands, forming a hierarchy. Arguments + defined at the upper level command are automatically added to all nested + commands. Nested commands example (assuming <c>progname</c> is <c>nested</c>): + </p> + + <code> +cli() -> + #{ + %% top level argument applicable to all commands + arguments => [#{name => top}], + commands => #{ + "first" => #{ + %% argument applicable to "first" command and + %% all commands nested into "first" + arguments => [#{name => mid}], + commands => #{ + "second" => #{ + %% argument only applicable for "second" command + arguments => [#{name => bottom}], + handler => fun (A) -> io:format("~p~n", [A]) end + } + } + } + } + }. + </code> + + <p>In the example above, a 3-level hierarchy is defined. First is the script + itself (<c>nested</c>), accepting the only argument <c>top</c>. Since it + has no associated handler, <seemfa marker="#run/3">run/3</seemfa> will + not accept user input omitting nested command selection. For this example, + user has to supply 5 arguments in the command line, two being command + names, and another 3 - required positional arguments:</p> + + <code> +./nested.erl one first second two three +#{top => "one",mid => "two",bottom => "three"} + </code> + + <p>Commands have preference over positional argument values. In the example + above, commands and positional arguments are interleaving, and <c>argparse</c> + matches command name first.</p> + + </section> + + <section> + <title>Arguments</title> + <p><c>argparse</c> supports positional and optional arguments. Optional arguments, + or options for short, must be prefixed with a special character (<c>-</c> is the default + on all operating systems). Both options and positional arguments have 1 or more associated + values. See <seetype marker="#argument"><c>argument specification</c></seetype> to + find more details about supported combinations.</p> + + <p>In the user input, short options may be concatenated with their values. Long + options support values separated by <c>=</c>. Consider this definition:</p> + + <code> +cli() -> + #{ + arguments => [ + #{name => long, long => "-long"}, + #{name => short, short => $s} + ], + handler => fun (Args) -> io:format("~p~n", [Args]) end + }. + </code> + + <p>Running <c>./args --long=VALUE</c> prints <c>#{long => "VALUE"}</c>, running + <c>./args -sVALUE</c> prints <c>#{short => "VALUE"}</c></p> + + <p><c>argparse</c> supports boolean flags concatenation: it is possible to shorten + <c>-r -f -v</c> to <c>-rfv</c>.</p> + + <p>Shortened option names are not supported: it is not possible to use <c>--my-argum</c> + instead of <c>--my-argument-name</c> even when such option can be unambiguously found.</p> + </section> + + <datatypes> + <datatype> + <name name="arg_type"/> + <desc> + <p>Defines type conversion applied to the string retrieved from the user input. + If the conversion is successful, resulting value is validated using optional + <c>Choices</c>, or minimums and maximums (for integer and floating point values + only). Strings and binary values may be validated using regular expressions. + It's possible to define custom type conversion function, accepting a string + and returning Erlang term. If this function raises error with <c>badarg</c> + reason, argument is treated as invalid. + </p> + </desc> + </datatype> + + <datatype> + <name name="argument_help"/> + <desc> + <p>User-defined help template to print in the command usage. First element of + a tuple must be a string. It is printed as a part of the usage header. Second + element of the tuple can be either a string printed as-is, a list + containing strings, <c>type</c> and <c>default</c> atoms, or a user-defined + function that must return a string.</p> + </desc> + </datatype> + + <datatype> + <name name="argument_name"/> + <desc> + <p>Argument name is used to populate argument map.</p> + </desc> + </datatype> + + <datatype> + <name name="argument"/> + <desc> + <p>Argument specification. Defines a single named argument that is returned + in the <seetype marker="#arg_map"><c>argument map</c></seetype>. The only + required field is <c>name</c>, all other fields have defaults.</p> + <p>If either of the <c>short</c> or <c>long</c> fields is specified, the + argument is treated as optional. Optional arguments do not have specific + order and may appear anywhere in the command line. Positional arguments + are ordered the same way as they appear in the arguments list of the command + specification.</p> + <p>By default, all positional arguments must be present in the command line. + The parser will return an error otherwise. Options, however, may be omitted, + in which case resulting argument map will either contain the default value, + or not have the key at all.</p> + <taglist> + <tag><c>name</c></tag> + <item> + <p>Sets the argument name in the parsed argument map. If <c>help</c> is not defined, + name is also used to generate the default usage message. + </p> + </item> + <tag><c>short</c></tag> + <item> + <p>Defines a short (single character) form of an optional argument.</p> + <code> +%% Define a command accepting argument named myarg, with short form $a: +1> Cmd = #{arguments => [#{name => myarg, short => $a}]}. +%% Parse command line "-a str": +2> {ok, ArgMap, _, _} = argparse:parse(["-a", "str"], Cmd), ArgMap. + +#{myarg => "str"} + +%% Option value can be concatenated with the switch: "-astr" +3> {ok, ArgMap, _, _} = argparse:parse(["-astr"], Cmd), ArgMap. + +#{myarg => "str"} + </code> + <p>By default all options expect a single value following the option switch. + The only exception is an option of a boolean type.</p> + </item> + <tag><c>long</c></tag> + <item> + <p>Defines a long form of an optional argument.</p> + <code> +1> Cmd = #{arguments => [#{name => myarg, long => "name"}]}. +%% Parse command line "-name Erlang": +2> {ok, ArgMap, _, _} = argparse:parse(["-name", "Erlang"], Cmd), ArgMap. + +#{myarg => "Erlang"} +%% Or use "=" to separate the switch and the value: +3> {ok, ArgMap, _, _} = argparse:parse(["-name=Erlang"], Cmd), ArgMap. + +#{myarg => "Erlang"} + </code> + <p>If neither <c>short</c> not <c>long</c> is defined, the + argument is treated as positional.</p> + </item> + <tag><c>required</c></tag> + <item> + <p>Forces the parser to expect the argument to be present in the + command line. By default, all positional argument are required, + and all options are not.</p> + </item> + <tag><c>default</c></tag> + <item> + <p>Specifies the default value to put in the parsed argument map + if the value is not supplied in the command line.</p> + <code> +1> argparse:parse([], #{arguments => [#{name => myarg, short => $m}]}). + +{ok,#{}, ... +2> argparse:parse([], #{arguments => [#{name => myarg, short => $m, default => "def"}]}). + +{ok,#{myarg => "def"}, ... + </code> + </item> + <tag><c>type</c></tag> + <item> + <p>Defines type conversion and validation routine. The default is <c>string</c>, + assuming no conversion.</p> + </item> + <tag><c>nargs</c></tag> + <item> + <p>Defines the number of following arguments to consume from the command line. + By default, the parser consumes the next argument and converts it into an + Erlang term according to the specified type. + </p> + <taglist> + <tag><c>pos_integer()</c></tag> + <item><p> Consume exactly this number of positional arguments, fail if there + is not enough. Value in the argument map contains a list of exactly this + length. Example, defining a positional argument expecting 3 integer values:</p> + <code> +1> Cmd = #{arguments => [#{name => ints, type => integer, nargs => 3}]}, +argparse:parse(["1", "2", "3"], Cmd). + +{ok, #{ints => [1, 2, 3]}, ... + </code> + <p>Another example defining an option accepted as <c>-env</c> and + expecting two string arguments:</p> + <code> +1> Cmd = #{arguments => [#{name => env, long => "env", nargs => 2}]}, +argparse:parse(["-env", "key", "value"], Cmd). + +{ok, #{env => ["key", "value"]}, ... + </code> + </item> + <tag><c>list</c></tag> + <item> + <p>Consume all following arguments until hitting the next option (starting + with an option prefix). May result in an empty list added to the arguments + map.</p> + <code> +1> Cmd = #{arguments => [ + #{name => nodes, long => "nodes", nargs => list}, + #{name => verbose, short => $v, type => boolean} +]}, +argparse:parse(["-nodes", "one", "two", "-v"], Cmd). + +{ok, #{nodes => ["one", "two"], verbose => true}, ... + </code> + </item> + <tag><c>nonempty_list</c></tag> + <item> + <p>Same as <c>list</c>, but expects at least one argument. Returns an error + if the following command line argument is an option switch (starting with the + prefix).</p> + </item> + <tag><c>'maybe'</c></tag> + <item> + <p>Consumes the next argument from the command line, if it does not start + with an option prefix. Otherwise, adds a default value to the arguments + map.</p> + <code> +1> Cmd = #{arguments => [ + #{name => level, short => $l, nargs => 'maybe', default => "error"}, + #{name => verbose, short => $v, type => boolean} +]}, +argparse:parse(["-l", "info", "-v"], Cmd). + +{ok,#{level => "info",verbose => true}, ... + +%% When "info" is omitted, argument maps receives the default "error" +2> argparse:parse(["-l", "-v"], Cmd). + +{ok,#{level => "error",verbose => true}, ... + </code> + </item> + <tag><c>{'maybe', term()}</c></tag> + <item> + <p>Consumes the next argument from the command line, if it does not start + with an option prefix. Otherwise, adds a specified Erlang term to the + arguments map.</p> + </item> + <tag><c>all</c></tag> + <item> + <p>Fold all remaining command line arguments into a list, ignoring + any option prefixes or switches. Useful for proxying arguments + into another command line utility.</p> + <code> +1> Cmd = #{arguments => [ + #{name => verbose, short => $v, type => boolean}, + #{name => raw, long => "-", nargs => all} +]}, +argparse:parse(["-v", "--", "-kernel", "arg", "opt"], Cmd). + +{ok,#{raw => ["-kernel","arg","opt"],verbose => true}, ... + </code> + </item> + </taglist> + </item> + <tag><c>action</c></tag> + <item> + <p>Defines an action to take when the argument is found in the command line. The + default action is <c>store</c>.</p> + <taglist> + <tag><c>store</c></tag> + <item><p> + Store the value in the arguments map. Overwrites the value previously written. + </p> + <code> +1> Cmd = #{arguments => [#{name => str, short => $s}]}, +argparse:parse(["-s", "one", "-s", "two"], Cmd). + +{ok, #{str => "two"}, ... + </code> + </item> + <tag><c>{store, term()}</c></tag> + <item><p> + Stores the specified term instead of reading the value from the command line. + </p> + <code> +1> Cmd = #{arguments => [#{name => str, short => $s, action => {store, "two"}}]}, +argparse:parse(["-s"], Cmd). + +{ok, #{str => "two"}, ... + </code> + </item> + <tag><c>append</c></tag> + <item><p> + Appends the repeating occurrences of the argument instead of overwriting. + </p> + <code> +1> Cmd = #{arguments => [#{name => node, short => $n, action => append}]}, +argparse:parse(["-n", "one", "-n", "two", "-n", "three"], Cmd). + +{ok, #{node => ["one", "two", "three"]}, ... + +%% Always produces a list - even if there is one occurrence +2> argparse:parse(["-n", "one"], Cmd). + +{ok, #{node => ["one"]}, ... + </code> + </item> + <tag><c>{append, term()}</c></tag> + <item><p> + Same as <c>append</c>, but instead of consuming the argument from the + command line, appends a provided <c>term()</c>. + </p></item> + <tag><c>count</c></tag> + <item><p> + Puts a counter as a value in the arguments map. Useful for implementing + verbosity option: + </p> + <code> +1> Cmd = #{arguments => [#{name => verbose, short => $v, action => count}]}, +argparse:parse(["-v"], Cmd). + +{ok, #{verbose => 1}, ... + +2> argparse:parse(["-vvvv"], Cmd). + +{ok, #{verbose => 4}, ... + </code> + </item> + <tag><c>extend</c></tag> + <item><p> + Works as <c>append</c>, but flattens the resulting list. + Valid only for <c>nargs</c> set to <c>list</c>, <c>nonempty_list</c>, + <c>all</c> or <c>pos_integer()</c>. + </p> + <code> +1> Cmd = #{arguments => [#{name => duet, short => $d, nargs => 2, action => extend}]}, +argparse:parse(["-d", "a", "b", "-d", "c", "d"], Cmd). + +{ok, #{duet => ["a", "b", "c", "d"]}, ... + +%% 'append' would result in {ok, #{duet => [["a", "b"],["c", "d"]]}, + </code> + </item> + </taglist> + </item> + <tag><c>help</c></tag> + <item> + <p>Specifies help/usage text for the argument. <c>argparse</c> provides automatic + generation based on the argument name, type and default value, but for better + usability it is recommended to have a proper description. Setting this field + to <c>hidden</c> suppresses usage output for this argument.</p> + </item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="arg_map"/> + <desc> + <p>Arguments map is the map of argument names to the values extracted from the + command line. It is passed to the matching command handler. + If an argument is omitted, but has the default value is specified, + it is added to the map. When no default value specified, and argument is not + present in the command line, corresponding key is not present in the resulting + map.</p> + </desc> + </datatype> + + <datatype> + <name name="handler"/> + <desc> + <p>Command handler specification. Called by <seemfa marker="#run/3"><c>run/3</c> + </seemfa> upon successful parser return.</p> + <taglist> + <tag><c>fun((arg_map()) -> term())</c></tag> + <item><p> + Function accepting <seetype marker="#arg_map"><c>argument map</c></seetype>. + See the basic example in the <seeerl marker="#quick-start">Quick Start</seeerl> + section. + </p></item> + <tag><c>{Module :: module(), Function :: atom()}</c></tag> + <item><p> + Function named <c>Function</c>, exported from <c>Module</c>, accepting + <seetype marker="#arg_map"><c>argument map</c></seetype>. + </p></item> + <tag><c>{fun(() -> term()), Default :: term()}</c></tag> + <item><p> + Function accepting as many arguments as there are in the <c>arguments</c> + list for this command. Arguments missing from the parsed map are replaced + with the <c>Default</c>. Convenient way to expose existing functions. + </p> + <code> +1> Cmd = #{arguments => [ + #{name => x, type => float}, + #{name => y, type => float, short => $p}], + handler => {fun math:pow/2, 1}}, +argparse:run(["2", "-p", "3"], Cmd, #{}). + +8.0 + +%% default term 1 is passed to math:pow/2 +2> argparse:run(["2"], Cmd, #{}). + +2.0 + </code> + </item> + <tag><c>{Module :: module(), Function :: atom(), Default :: term()}</c></tag> + <item><p>Function named <c>Function</c>, exported from <c>Module</c>, accepting + as many arguments as defined for this command. Arguments missing from the parsed + map are replaced with the <c>Default</c>. Effectively, just a different syntax + to the same functionality as demonstrated in the code above.</p></item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="command_help"/> + <desc> + <p>User-defined help template. Use this option to mix custom and predefined usage text. + Help template may contain unicode strings, and following atoms:</p> + <taglist> + <tag>usage</tag> + <item><p> + Formatted command line usage text, e.g. <c>rm [-rf] <directory></c>. + </p></item> + <tag>commands</tag> + <item><p> + Expanded list of sub-commands. + </p></item> + <tag>arguments</tag> + <item><p> + Detailed description of positional arguments. + </p></item> + <tag>options</tag> + <item><p> + Detailed description of optional arguments. + </p></item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="command"/> + <desc> + <p>Command specification. May contain nested commands, forming a hierarchy.</p> + <taglist> + <tag><c>commands</c></tag> + <item><p> + Maps of nested commands. Keys must be strings, matching command line input. + Basic utilities do not need to specify any nested commands. + </p> + </item> + <tag><c>arguments</c></tag> + <item><p> + List of arguments accepted by this command, and all nested commands in the + hierarchy. + </p></item> + <tag><c>help</c></tag> + <item><p> + Specifies help/usage text for this command. Pass <c>hidden</c> to remove + this command from the usage output. + </p></item> + <tag><c>handler</c></tag> + <item><p> + Specifies a callback function to call by <seemfa marker="#run/3">run/3</seemfa> + when the parser is successful. + </p></item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="cmd_path"/> + <desc> + <p>Path to the nested command. First element is always the <c>progname</c>, + subsequent elements are nested command names.</p> + </desc> + </datatype> + + <datatype> + <name name="parser_error"/> + <desc> + <p>Returned from <seemfa marker="#parse/3"><c>parse/2,3</c></seemfa> when the + user input cannot be parsed according to the command specification.</p> + <p>First element is the path to the command that was considered when the + parser detected an error. Second element, <c>Expected</c>, is the argument + specification that caused an error. It could be <c>undefined</c>, meaning + that <c>Actual</c> argument had no corresponding specification in the + arguments list for the current command. </p> + <p>When <c>Actual</c> is set to <c>undefined</c>, it means that a required + argument is missing from the command line. If both <c>Expected</c> and + <c>Actual</c> have values, it means validation error.</p> + <p>Use <seemfa marker="#format_error/1"><c>format_error/1</c></seemfa> to + generate a human-readable error description, unless there is a need to + provide localised error messages.</p> + </desc> + </datatype> + + <datatype> + <name name="parser_options"/> + <desc> + <p>Options changing parser behaviour.</p> + <taglist> + <tag><c>prefixes</c></tag> + <item><p> + Changes the option prefix (the default is <c>-</c>). + </p></item> + <tag><c>default</c></tag> + <item><p> + Specifies the default value for all optional arguments. When + this field is set, resulting argument map will contain all + argument names. Useful for easy pattern matching on the + argument map in the handler function. + </p></item> + <tag><c>progname</c></tag> + <item><p> + Specifies the program (root command) name. Returned as the + first element of the command path, and printed in help/usage + text. It is recommended to have this value set, otherwise the + default one is determined with <c>init:get_argument(progname)</c> + and is often set to <c>erl</c> instead of the actual script name. + </p></item> + <tag><c>command</c></tag> + <item><p> + Specifies the path to the nested command for + <seemfa marker="#help/2"><c>help/2</c></seemfa>. Useful to + limit output for complex utilities with multiple commands, + and used by the default error handling logic. + </p></item> + <tag><c>columns</c></tag> + <item><p> + Specifies the help/usage text width (characters) for + <seemfa marker="#help/2"><c>help/2</c></seemfa>. Default value + is 80. + </p></item> + </taglist> + </desc> + </datatype> + + <datatype> + <name name="parse_result"/> + <desc> + <p>Returned from <seemfa marker="#parse/3"><c>parse/2,3</c></seemfa>. Contains + arguments extracted from the command line, path to the nested command (if any), + and a (potentially nested) command specification that was considered when + the parser finished successfully. It is expected that the command contains + a handler definition, that will be called passing the argument map.</p> + </desc> + </datatype> + + </datatypes> + + <funcs> + + <func> + <name name="format_error" arity="1" since="OTP 26.0"/> + <fsummary>Generates human-readable text for parser errors.</fsummary> + <desc> + <p>Generates human-readable text for + <seetype marker="#parser_error"><c>parser error</c></seetype>. Does + not include help/usage information, and does not provide localisation. + </p> + </desc> + </func> + + <func> + <name name="help" arity="1" since="OTP 26.0"/> + <name name="help" arity="2" since="OTP 26.0"/> + <fsummary>Generates help/usage information text.</fsummary> + <desc> + <p>Generates help/usage information text for the command + supplied, or any nested command when <c>command</c> + option is specified. Does not provide localisaton. + Expects <c>progname</c> to be set, otherwise defaults to + return value of <c>init:get_argument(progname)</c>.</p> + </desc> + </func> + + <func> + <name name="parse" arity="2" since="OTP 26.0"/> + <name name="parse" arity="3" since="OTP 26.0"/> + <fsummary>Parses command line arguments according to the command specification.</fsummary> + <desc> + <p>Parses command line arguments according to the command specification. + Raises an exception if the command specification is not valid. Use + <seemfa marker="erl_error#format_exception/3"><c>erl_error:format_exception/3,4</c> + </seemfa> to see a friendlier message. Invalid command line input + does not raise an exception, but makes <c>parse/2,3</c> to return a tuple + <seetype marker="#parser_error"><c>{error, parser_error()}</c></seetype>. + </p> + <p>This function does not call command handler.</p> + </desc> + </func> + + <func> + <name name="run" arity="3" since="OTP 26.0"/> + <fsummary>Parses command line arguments and calls the matching command handler.</fsummary> + <desc> + <p>Parses command line arguments and calls the matching command handler. + Prints human-readable error, help/usage information for the discovered + command, and halts the emulator with code 1 if there is any error in the + command specification or user-provided command line input. + </p> + <warning> + <p>This function is designed to work as an entry point to a standalone + <seecom marker="erts:escript"><c>escript</c></seecom>. Therefore, it halts + the emulator for any error detected. Do not use this function through + remote procedure call, or it may result in an unexpected shutdown of a remote + node.</p> + </warning> + </desc> + </func> + + </funcs> + +</erlref> + |