pax_global_header00006660000000000000000000000064126061421140014507gustar00rootroot0000000000000052 comment=b8c14144c20ddc29ea04684b34d2c659d8780f38 lua_cliargs-2.5-4/000077500000000000000000000000001260614211400140035ustar00rootroot00000000000000lua_cliargs-2.5-4/.env000066400000000000000000000000741260614211400145750ustar00rootroot00000000000000GITHUB_USER="amireh" GITHUB_REPO="lua_cliargs" GITHUB_TOKEN=lua_cliargs-2.5-4/.gitignore000066400000000000000000000001031260614211400157650ustar00rootroot00000000000000/luacov.report.out /luacov.stats.out /.env.local /*.rock **/.*.swp lua_cliargs-2.5-4/.travis.yml000066400000000000000000000003601260614211400161130ustar00rootroot00000000000000language: erlang otp_release: - R15B02 env: - LUA="" - LUA="luajit" branches: only: - master install: - sudo apt-get install luajit - sudo apt-get install luarocks - sudo luarocks install busted script: "busted spec" lua_cliargs-2.5-4/LICENSE000066400000000000000000000020401260614211400150040ustar00rootroot00000000000000Copyright (c) 2012 Ahmad Amireh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua_cliargs-2.5-4/README.md000066400000000000000000000176041260614211400152720ustar00rootroot00000000000000# cliargs [![travis-ci status](https://secure.travis-ci.org/amireh/lua_cliargs.png)](http://travis-ci.org/#!/amireh/lua_cliargs/builds) cliargs is a command-line argument parser for Lua. It supports several types of arguments: 1. required arguments 1. optional arguments with different notations: `-short-key VALUE` and/or `--expanded-key=VALUE` 2. optional arguments with multiple-values that get appended to a list 1. optional "flag" arguments (on/off options) with notations: `-short-key` and/or `--expanded-key` 1. a single optional "splat" argument which can be repeated (must be the last argument) Optional arguments can have default values (strings), flags always default to 'true'. ## Usage Example See `example.lua` for an example on how to use the parser. Try it with the following sample command lines; ``` example.lua --help example.lua -o myfile -d --compress=gzip inputfile example.lua --__DUMP__ -o myfile -d --compress=gzip inputfile ``` **Accessing arguments** All types of arguments must specify a *key*. In the case of required arguments, the keys are only used in the help listings. However, for optional arguments, they are mandatory (either *--key* or *--extended-key* must be specified, the other is optional). The `parse()` method will parse the command line and return a table with results. Accessing argument or option values in this table can be done using the key with the leading dashes omitted (`-` or `--`). When defining an option (or a flag) , you can access it using either key or expanded-key; they'll both be defined. ## Help listings `--help` A help listing will be automatically generated and accessed using the `--help` argument. You can also force its display in the code using `cli:print_help()`. This is the result for our example (see examples/00_general.lua): ``` Usage: cli_example.lua [OPTIONS] INPUT [OUTPUT-1 [OUTPUT-2 [...]]] ARGUMENTS: INPUT path to the input file (required) OUTPUT multiple output paths (optional, default: /dev/stdout) OPTIONS: -c, --compress=FILTER the filter to use for compressing output: gzip, lzma, bzip2, or none (default: gzip) -o FILE path to output file (default: /dev/stdout) -d script will run in DEBUG mode -v, --version prints the program's version and exits --verbose the script output will be very verbose ``` ## Validations ### Runtime argument validation From a parsing point of view, there are 3 cases that need to be handled which are outlined below. If I missed something, please open a ticket! **Missing a required argument** ``` $ lua examples/00_general.lua cli_example.lua: error: bad number of arguments; 1-4 argument(s) must be specified, not 0; re-run with --help for usage. ``` **Missing value for an optional argument** ``` $ lua examples/00_general.lua --compress inputfile cli_example.lua: error: option --compress requires a value to be set; re-run with --help for usage. ``` **Unknown arguments** ``` $ lua examples/00_general.lua -f inputfile cli_example.lua: error: unknown/bad flag; -f; re-run with --help for usage. ``` ### Some sanity guards In the following cases, `cliargs` will report an error to you and terminate the running script: 1. flag options can not accept a value. For example: `cli:add_flag('-v VERSION')` will return an error 2. duplicate keys are not allowed: defining two options with the key `--input` will be rejected ## Tests Running test specs is done using [busted](http://olivinelabs.com/busted/). You can install it using [LuaRocks](http://www.luarocks.org/), and then just call it with the `spec` folder: ``` luarocks install busted cd /path/to/lua_cliargs/ busted spec ``` ## Contributions If you come across a bug and you'd like to patch it, please fork the repository, commit your patch, and request a pull. ## Thanks to Many thanks to everyone who reported bugs, provided fixes, and added entirely new features: 1. [Thijs Schreijer](https://github.com/Tieske) 1. [Jack Lawson](https://github.com/ajacksified) 1. [Robert Andrew Ditthardt](https://github.com/DorianGray) 1. [Oscar Lim](https://github.com/o-lim) *If I missed you, don't hesitate to update this file or just email me.* ## Reference A function reference was generated using [LunaDoc](http://jgm.github.com/lunamark/lunadoc.1.html) which can be found [here](http://lua-cliargs.docs.mxvt.net). ## Changelog Changes from 2.5.1 to 2.5.2 - No longer tracking the (legacy) tarballs in git or the luarocks package. Instead, we use the GitHub release tarballs for each version. Changes in 2.4.0 from 2.3-4 1. All arguments now accept a callback that will be invoked when parsing of those arguments was successful 2. (**POSSIBLY BREAKING**) Default value for flags is now `nil` instead of `false`. This will only affect existing behavior if you were explicitly testing unset flags to equal `false` (i.e. `if flag == false then`) as opposed to `if flag then` (or `if not flag then`). 3. Minor bugfixes Changes in 2.3.0 1. the parser will now understand `--` to denote the end of optional arguments and will map whatever comes after it to required/splat args 2. `-short VALUE` is now properly supported, so is `-short=VALUE` 3. short-key options can now officially be composed of more than 1 character 4. the parser now accepts callbacks that will be invoked as soon as options are parsed so that you can bail out of parsing preemptively (like for `--version` or `--help` options) 5. options can now accept multiple values via multiple invocations if a table was provided as a default value (passed-in values will be appended to that list) Changes in 2.2-0 from 2.1-2 1. the `=` that separates keys from values in the `--expanded-key` notation is no longer mandatory; using either a space or a `=` will map the value to the key (e.g., `--compress lzma` is equal to `--compress=lzma`) Changes in 2.0.0 from 1.x.x 1. added the 'splat' argument, an optional repetitive argument for which a maximum number of occurrences can be set 1. removed the reference, arguments are now solely returned by their key/expanded-key (BREAKING!) 1. removed object overhead and the `new()` method as the library will only be used once on program start-up (BREAKING!) 1. after parsing completed successfully, the library will effectively delete itself to free resources (BREAKING!) 1. option/flag is now allowed with only an expanded-key defined 1. Debug aid implemented; adding a first option `--__DUMP__`, will dump the results of parsing the command line. Especially for testing how to use the commandline with arguments containing spaces either quoted or not. 1. the `print_usage()` and `print_help()` now have a 'noprint' parameter that will not print the message, but return it as an error string (`nil + errmsg`) ## License The code is released under the MIT terms. Feel free to use it in both open and closed software as you please. Copyright (c) 2011-2012 Ahmad Amireh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua_cliargs-2.5-4/bin/000077500000000000000000000000001260614211400145535ustar00rootroot00000000000000lua_cliargs-2.5-4/bin/coverage000077500000000000000000000004471260614211400163010ustar00rootroot00000000000000#!/usr/bin/env bash # Run busted and collect spec coverage using LuaCov. # Output will be found at /luacov.report.out. # # Usage: # # $ ./bin/coverage # $ cat luacov.report.out busted -c luacov src/cliargs.lua rm luacov.stats.out grep -zPo "(?s)={10,}\nSummary\n={10,}.+" luacov.report.outlua_cliargs-2.5-4/bin/release000077500000000000000000000045721260614211400161310ustar00rootroot00000000000000#!/usr/bin/env bash [ -f ".env" ] && source ".env" [ -f ".env.local" ] && source ".env.local" function abort { echo -e "\e[00;31m[ FAILED ]\e[00m ${1}" exit 1 } function confirm { echo "${1} [y/N]" read confirmation if [ "${confirmation}" != "y" ]; then exit 0 fi } [ -z "${GITHUB_TOKEN}" ] && abort "Missing GITHUB_TOKEN env variable." [ -z "${GITHUB_USER}" ] && abort "Missing GITHUB_USER env variable." [ -z "${GITHUB_REPO}" ] && abort "Missing GITHUB_REPO env variable." [ -z "${LUAROCKS_API_KEY}" ] && abort "Missing LUAROCKS_API_KEY env variable." VERSION=$1 SRC_FILE="src/cliargs.lua" # VERSION=$(grep "version" lua_cliargs-*.rockspec | cut -d' ' -f3 | sed 's/"//g') SRC_VERSION=$(grep "_VERSION" src/cliargs.lua | sed -e 's/.*=//' -e 's/.* //' -e 's/"//g') NEW_ROCKSPEC="lua_cliargs-${VERSION}.rockspec" OLD_ROCKSPEC="lua_cliargs-${SRC_VERSION}.rockspec" if [ "${VERSION}" == "${SRC_VERSION}" ]; then abort "Version specified is the same as the current one in rockspec" fi # Publish to GitHub JSON_PAYLOAD=$( printf '{ "tag_name": "v%s", "target_commitish": "master", "name": "v%s", "body": "Release of version %s", "draft": false, "prerelease": false }' $VERSION $VERSION $VERSION ) echo $JSON_PAYLOAD echo "Releasing version ${VERSION}..." if [ ! -f $OLD_ROCKSPEC ]; then abort "Version in ${SRC_FILE} does not match the rockspec file!" fi # rename rockspec file mv $OLD_ROCKSPEC $NEW_ROCKSPEC # bump version in rockspec perl -p -i -e "s/${SRC_VERSION}/${VERSION}/g" $NEW_ROCKSPEC # bump version in src perl -p -i -e "s/${SRC_VERSION}/${VERSION}/" $SRC_FILE confirm "rockspec and source file have been modified, please confirm the changes. Proceed?" echo "Creating git release v${VERSION}..." git add $NEW_ROCKSPEC git rm $OLD_ROCKSPEC git add $SRC_FILE git commit -m "Release v${VERSION}" git push origin master echo "Done." confirm "Create a new GitHub release?" # the API will automatically create the tag for us, no need to do it manually! curl \ --data "$JSON_PAYLOAD" \ -X POST \ -H "Content-Type: application/json; charset=utf-8" \ -H "Accept: application/json" \ "https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/releases?access_token=${GITHUB_TOKEN}" echo "Done." confirm "Publish to luarocks?" luarocks --api-key=$LUAROCKS_API_KEY upload $NEW_ROCKSPEC echo -e "\e[00;32m[ SUCCESS ]\e[00m" lua_cliargs-2.5-4/doc/000077500000000000000000000000001260614211400145505ustar00rootroot00000000000000lua_cliargs-2.5-4/doc/cliargs.html000066400000000000000000000145071260614211400170710ustar00rootroot00000000000000 cliargs

cliargs

cli:set_name(name)

Assigns the name of the program which will be used for logging.

cli:add_arg(key, desc)

Defines a required argument. Required arguments have no special notation and are order-sensitive. Note: the value will be stored in args[@key]. Aliases: add_argument

Parameters

  1. key: the argument’s “name” that will be displayed to the user
  2. desc: a description of the argument

Usage example

The following will parse the argument (if specified) and set its value in args["root"]: cli:add_arg("root", "path to where root scripts can be found")

cli:optarg(key, desc, default, maxcount)

Defines an optional argument (or more than one). There can be only 1 optional argument, and is has to be the last one on the argumentlist. Note: the value will be stored in args[@key]. The value will be a ‘string’ if ‘maxcount == 1’, or a table if ‘maxcount > 1’

Parameters

  1. key: the argument’s “name” that will be displayed to the user
  2. desc: a description of the argument
  3. default: optional; specify a default value (the default is "")
  4. maxcount: optional; specify the maximum number of occurences allowed (default is 1)

Usage example

The following will parse the argument (if specified) and set its value in args["root"]: cli:add_arg("root", "path to where root scripts can be found", "", 2) The value returned will be a table with at least 1 entry and a maximum of 2 entries

cli:add_opt(key, desc, default)

Defines an option. Optional arguments can use 3 different notations, and can accept a value. Aliases: add_option

Parameters

  1. key: the argument identifier, can be either -key, or -key, --expanded-key: if the first notation is used then a value can be defined after a space ('-key VALUE'), if the 2nd notation is used then a value can be defined after an = ('-key, --expanded-key=VALUE'). As a final option it is possible to only use the expanded key (eg. '--expanded-key') both with and without a value specified.
  2. desc: a description for the argument to be shown in –help
  3. default: optional; specify a default value (the default is "")

Usage example

The following option will be stored in args["i"] and args["input"] with a default value of my_file.txt: cli:add_option("-i, --input=FILE", "path to the input file", "my_file.txt")

cli:add_flag(key, desc)

Define a flag argument (on/off). This is a convenience helper for cli.addopt(). See cli.addopt() for more information.

Parameters

  1. key: the argument’s key
  2. desc: a description of the argument to be displayed in the help listing

cli:parse(noprint, dump)

Parses the arguments found in #arg and returns a table with the populated values. (NOTE: after succesful parsing, the module will delete itself to free resources) Aliases: parse_args

Parameters

  1. noprint: set this flag to prevent any information (error or help info) from being printed
  2. dump: set this flag to dump the parsed variables for debugging purposes, alternatively set the first option to –DEBUG (option with 2 trailing and leading underscores) to dump at runtime.

Returns

  1. a table containing the keys specified when the arguments were defined along with the parsed values, or nil + error message (–help option is considered an error and returns nil + help message)

cli:print_usage(noprint)

Prints the USAGE heading.

Parameters

  1. noprint: set this flag to prevent the line from being printed

Returns

  1. a string with the USAGE message.

cli:print_help(noprint)

Prints the HELP information.

Parameters

  1. noprint: set this flag to prevent the information from being printed

Returns

  1. a string with the HELP message.

cli:set_colsz(key_cols, desc_cols)

Sets the amount of space allocated to the argument keys and descriptions in the help listing. The sizes are used for wrapping long argument keys and descriptions.

Parameters

  1. key_cols: the number of columns assigned to the argument keys, set to 0 to auto detect (default: 0)
  2. desc_cols: the number of columns assigned to the argument descriptions, set to 0 to auto set the total width to 72 (default: 0)

cliargs

lua_cliargs-2.5-4/doc/index.html000066400000000000000000000145071260614211400165540ustar00rootroot00000000000000 cliargs

cliargs

cli:set_name(name)

Assigns the name of the program which will be used for logging.

cli:add_arg(key, desc)

Defines a required argument. Required arguments have no special notation and are order-sensitive. Note: the value will be stored in args[@key]. Aliases: add_argument

Parameters

  1. key: the argument’s “name” that will be displayed to the user
  2. desc: a description of the argument

Usage example

The following will parse the argument (if specified) and set its value in args["root"]: cli:add_arg("root", "path to where root scripts can be found")

cli:optarg(key, desc, default, maxcount)

Defines an optional argument (or more than one). There can be only 1 optional argument, and is has to be the last one on the argumentlist. Note: the value will be stored in args[@key]. The value will be a ‘string’ if ‘maxcount == 1’, or a table if ‘maxcount > 1’

Parameters

  1. key: the argument’s “name” that will be displayed to the user
  2. desc: a description of the argument
  3. default: optional; specify a default value (the default is "")
  4. maxcount: optional; specify the maximum number of occurences allowed (default is 1)

Usage example

The following will parse the argument (if specified) and set its value in args["root"]: cli:add_arg("root", "path to where root scripts can be found", "", 2) The value returned will be a table with at least 1 entry and a maximum of 2 entries

cli:add_opt(key, desc, default)

Defines an option. Optional arguments can use 3 different notations, and can accept a value. Aliases: add_option

Parameters

  1. key: the argument identifier, can be either -key, or -key, --expanded-key: if the first notation is used then a value can be defined after a space ('-key VALUE'), if the 2nd notation is used then a value can be defined after an = ('-key, --expanded-key=VALUE'). As a final option it is possible to only use the expanded key (eg. '--expanded-key') both with and without a value specified.
  2. desc: a description for the argument to be shown in –help
  3. default: optional; specify a default value (the default is "")

Usage example

The following option will be stored in args["i"] and args["input"] with a default value of my_file.txt: cli:add_option("-i, --input=FILE", "path to the input file", "my_file.txt")

cli:add_flag(key, desc)

Define a flag argument (on/off). This is a convenience helper for cli.addopt(). See cli.addopt() for more information.

Parameters

  1. key: the argument’s key
  2. desc: a description of the argument to be displayed in the help listing

cli:parse(noprint, dump)

Parses the arguments found in #arg and returns a table with the populated values. (NOTE: after succesful parsing, the module will delete itself to free resources) Aliases: parse_args

Parameters

  1. noprint: set this flag to prevent any information (error or help info) from being printed
  2. dump: set this flag to dump the parsed variables for debugging purposes, alternatively set the first option to –DEBUG (option with 2 trailing and leading underscores) to dump at runtime.

Returns

  1. a table containing the keys specified when the arguments were defined along with the parsed values, or nil + error message (–help option is considered an error and returns nil + help message)

cli:print_usage(noprint)

Prints the USAGE heading.

Parameters

  1. noprint: set this flag to prevent the line from being printed

Returns

  1. a string with the USAGE message.

cli:print_help(noprint)

Prints the HELP information.

Parameters

  1. noprint: set this flag to prevent the information from being printed

Returns

  1. a string with the HELP message.

cli:set_colsz(key_cols, desc_cols)

Sets the amount of space allocated to the argument keys and descriptions in the help listing. The sizes are used for wrapping long argument keys and descriptions.

Parameters

  1. key_cols: the number of columns assigned to the argument keys, set to 0 to auto detect (default: 0)
  2. desc_cols: the number of columns assigned to the argument descriptions, set to 0 to auto set the total width to 72 (default: 0)

cliargs

lua_cliargs-2.5-4/doc/lunadoc.css000066400000000000000000000006331260614211400167110ustar00rootroot00000000000000body { font-family: Georgia, serif; } h3.declaration { margin-bottom: 0.5em; } div.section { clear: both; border-top: 2px solid #eee; } code,pre { font-family: Courier, monospace; font-size: 90%; } div#index { position: absolute; left: 1em; top: 1em; width:14em; } div#content { position: absolute; left: 15em; top: 0.5em; padding-left: 2em; max-width: 40em; padding-bottom: 1em; border-left: 1px solid #555; } lua_cliargs-2.5-4/examples/000077500000000000000000000000001260614211400156215ustar00rootroot00000000000000lua_cliargs-2.5-4/examples/00_general.lua000077500000000000000000000051301260614211400202420ustar00rootroot00000000000000--[[ Try this file with the following commands lines; example.lua --help example.lua -o myfile -d --compress=gzip inputfile example.lua --__DUMP__ -o myfile -d --compress=gzip inputfile --]] local cli = require "../src/cliargs" local function print_version(key, value, altkey) -- this is called when the flag -v or --version is set if key == 'version' then print("cli_example.lua: version 1.2.1") os.exit(0) end end cli:set_name("cli_example.lua") -- Required arguments: cli:add_argument("INPUT", "path to the input file") -- cli:add_argument("OUTPUT", "path to the output file") -- Using an alias for add_argument -- Optional (repetitive) arguments -- only the last argument can be optional. Being set to maximum 3 optionals. cli:optarg("OUTPUT", "multiple output paths", "/dev/stdout", 3) -- Optional parameters: cli:add_option("-c, --compress=FILTER", "the filter to use for compressing output: gzip, lzma, bzip2, or none", "gzip") cli:add_option("-o FILE", "path to output file", "/dev/stdout") -- Flags: a flag is a boolean option. Defaults to false -- A flag with short-key notation only cli:add_flag("-d", "script will run in DEBUG mode") -- A flag with both the short-key and --expanded-key notations, and callback function cli:add_flag("-v, --version", "prints the program's version and exits", print_version) -- A flag with --expanded-key notation only cli:add_flag("--verbose", "the script output will be very verbose") -- A flag that can be negated using --no- as a prefix, but you'll still have -- to access its value without that prefix. See below for an example. cli:add_flag('--[no-]ice-cream', 'ice cream, or not', true) -- Parses from _G['arg'] local args = cli:parse(arg) if not args then -- something wrong happened and an error was printed os.exit(1) elseif not args['ice-cream'] then print('kernel panic: NO ICE CREAM?!11') os.exit(1000) end -- argument parsing was successful, arguments can be found in `args` -- upon successful parsing cliargs will delete itslef to free resources -- for k,item in pairs(args) do print(k .. " => " .. tostring(item)) end print("Input file: " .. args["INPUT"]) print("Output file: " .. args["o"]) if #args.OUTPUT > 0 then print("Additional outputs:") if type(args.OUTPUT) == "string" then args.OUTPUT = { args.OUTPUT } end for i, out in ipairs(args.OUTPUT) do print(" " .. i .. ". " .. out) end end if #args['c'] == 0 or args['c'] == 'none' then print("Won't be compressing") else print("Compressing using " .. args['c']) end if args['ice-cream'] then print('And, one ice cream for you.') endlua_cliargs-2.5-4/examples/01_multiple_options.lua000066400000000000000000000022071260614211400222330ustar00rootroot00000000000000--[[ This example shows how to use multiple-value options that get appended into a list. Try this file with the following invocations; multiple_options.lua --help multiple_options.lua \ -i http://www.google.com \ -i http://www.yahoo.com \ -j 2 \ combined.html --]] local cli = require "cliargs" cli:set_name("example.lua") cli:optarg("OUTPUT", "Path to where the combined HTML output should be saved.", "./a.html") cli:add_option("-i URLs...", "A url to download. You can pass in as many as needed", {} --[[ this is the important bit! ]]) cli:add_option("-j THREADS", "Concurrency threshold; the higher the number, the more files will be downloaded in parallel.", "2") -- Parses from _G['arg'] local args = cli:parse_args() if not args then os.exit(1) -- something wrong happened and an error was printed end if #args.i > 0 then print("Source URLs:") for i, url in ipairs(args.i) do print(" " .. i .. ". " .. url) end print("Downloading ".. #args.i .. " files in " .. tonumber(args.j) .. " threads.") print("Output will be found at " .. args.OUTPUT) else print("No source URLs provided, nothing to do!") end lua_cliargs-2.5-4/examples/02_parse_callbacks.lua000066400000000000000000000016421260614211400217410ustar00rootroot00000000000000--[[ Shows how to define a callback to be invoked as soon as an option is parsed. Callbacks are useful for abruptive options like "--help" or "--version" where you might want to stop the execution of the parser/program if passed. Try this file with the following commands lines; example.lua --version example.lua -v example.lua --]] local cli = require "cliargs" local function print_version(key, value, altkey, opt) -- this is called when the flag -v or --version is set if key == 'version' then print("example.lua: version 1.2.1") os.exit(0) end end cli:set_name("try_my_version.lua") cli:add_flag("-v, --version", "prints the program's version and exits", print_version) -- Parses from _G['arg'] local args = cli:parse() if not args then -- something wrong happened and an error was printed os.exit(1) end -- if we got to this point, it means -v (or --version) were not passed: print "Why, hi!" lua_cliargs-2.5-4/lua_cliargs-2.5-4.rockspec000066400000000000000000000012401260614211400204630ustar00rootroot00000000000000package = "lua_cliargs" version = "2.5-4" source = { url = "https://github.com/amireh/lua_cliargs/archive/v2.5-4.tar.gz", dir = "lua_cliargs-2.5-4" } description = { summary = "A command-line argument parser.", detailed = [[ This module adds support for accepting CLI arguments easily using multiple notations and argument types. cliargs allows you to define required, optional, and flag arguments. ]], homepage = "https://github.com/amireh/lua_cliargs", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { cliargs = "src/cliargs.lua" } } lua_cliargs-2.5-4/spec/000077500000000000000000000000001260614211400147355ustar00rootroot00000000000000lua_cliargs-2.5-4/spec/cliargs_methods_spec.lua000066400000000000000000000266321260614211400216320ustar00rootroot00000000000000 -- some helper stuff for debugging local quoted = function(s) return "'" .. tostring(s) .. "'" end local dump = function(t) print(" ============= Dump " .. tostring(t) .. " =============") if type(t) ~= "table" then if type(t) == "string" then print(quoted(tostring(t))) else print(tostring(t)) end else for k,v in pairs(t) do if type(v) == "string" then print(quoted(k),quoted(v)) else print(quoted(k),tostring(v)) end end end print(" ============= Dump " .. tostring(t) .. " =============") end local cli -- start tests describe("Testing cliargs library methods/functions", function() describe("testing private functions", function() setup(function() _G._TEST = true package.loaded.cliargs = nil -- Busted uses it, but must force to reload to test it with _TEST cli = require("cliargs") end) teardown(function() _G._TEST = nil end) it("tests the private split() function", function() -- takes: str, split-char local expected, result result = cli.split("hello,world",",") expected = {"hello", "world"} assert.is.same(result, expected) result = cli.split("hello,world,",",") expected = {"hello", "world"} assert.is.same(result, expected) result = cli.split("hello",",") expected = {"hello"} assert.is.same(result, expected) result = cli.split("",",") expected = {} assert.is.same(result, expected) end) it("tests the private wordwrap() function", function() -- takes: text, size, padding local text = "123456789 123456789 123456789!" local expected, result result = cli.wordwrap(text, 10) expected = "123456789\n123456789\n123456789!" assert.is.same(result, expected) -- exact length + 1 overflow result = cli.wordwrap(text, 9) expected = "123456789\n123456789\n123456789\n!" assert.is.same(result, expected) result = cli.wordwrap(text, 9, nil, true) expected = "123456789\n123456789\n123456789!" assert.is.same(result, expected) result = cli.wordwrap(text, 8) expected = "12345678\n9\n12345678\n9\n12345678\n9!" assert.is.same(result, expected) end) it("tests the optarg() method", function() local key, desc, default, maxcount = "LastArg", "The lastarg description", "lastarg default", 3 local expected = { key = key, desc = desc, default = default, maxcount = maxcount} cli:optarg(key, desc, default, maxcount) assert.are.same(cli.optargument, expected) end) end) -- private functions describe("testing public functions", function() setup(function() _G._TEST = true package.loaded.cliargs = nil -- Busted uses it, but must force to reload to test it with _TEST cli = require("cliargs") end) teardown(function() _G._TEST = nil end) before_each(function() cli.optional = {} cli.required = {} end) after_each(function() end) it("tests the add_arg() method", function() -- takes: key, descr local key, desc = "argname", "thedescription" cli:add_arg(key, desc) assert.are.equal(cli.required[1].key, key) assert.are.equal(cli.required[1].desc, desc) end) describe("#add_opt()", function() describe("given a value indicator", function() it("should work with only a short-key", function() -- takes: key, descr, default local key, desc, default = "-i VALUE", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, false) assert.are.equal(cli.optional[1].default, default) end) it("should work with a short-key that is longer than 1 character", function() local key, desc, default = "-Xassembler OPTIONS", "Pass on to the assembler", "" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "Xassembler") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, false) assert.are.equal(cli.optional[1].default, default) end) it("should work with only expanded-key", function() -- takes: key, descr, default local key, desc, default = "--insert=VALUE", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].expanded_key, "insert") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, false) assert.are.equal(cli.optional[1].default, default) end) it("should work with combined short + expanded-key", function() -- takes: key, descr, default local key, desc, default = "-i, --insert=VALUE", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") assert.are.equal(cli.optional[1].expanded_key, "insert") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, false) assert.are.equal(cli.optional[1].default, default) end) it("should work with combined short + expanded-key, no comma between them", function() -- takes: key, descr, default local key, desc, default = "-i --insert=VALUE", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") assert.are.equal(cli.optional[1].expanded_key, "insert") end) end) describe("given no value indicator (implicit flags)", function() it("should work with a short-key", function() -- takes: key, descr, default local key, desc, default = "-i", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, true) assert.are.equal(cli.optional[1].default, nil) -- no value = flag type option, hence nil end) it("should work with a short-key that is longer than 1 character", function() -- takes: key, descr, default local key, desc, default = "-Wno-unsigned", "thedescription" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "Wno-unsigned") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, true) assert.are.equal(cli.optional[1].default, nil) -- no value = flag type option, hence nil end) it("should work with only expanded-key", function() -- takes: key, descr, default local key, desc, default = "--insert", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].expanded_key, "insert") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, true) assert.are.equal(cli.optional[1].default, nil) -- no value = flag type option, hence nil end) it("should work with combined short + expanded-key", function() -- takes: key, descr, default local key, desc, default = "-i, --insert", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") assert.are.equal(cli.optional[1].expanded_key, "insert") assert.are.equal(cli.optional[1].desc, desc) assert.are.equal(cli.optional[1].flag, true) assert.are.equal(cli.optional[1].default, nil) -- no value = flag type option, hence nil end) end) end) it("tests add_flag() for setting default value", function() -- takes: key, descr local key, desc = "-i, --insert", "thedescription" cli:add_flag(key, desc) assert.are.equal(cli.optional[1].flag, true) assert.are.equal(cli.optional[1].default, nil) end) it("tests add_flag() to error-out when providing a value", function() -- takes: key, descr local key, desc = "-i, --insert=VALUE", "thedescription" assert.is.error(function() cli:add_flag(key, desc) end) --'=VALUE' is not allowed for a flag end) it("tests add_arg() with a duplicate argument", function() -- takes: key, descr local key, desc = "argname", "thedescription" cli:add_arg(key, desc) assert.are.equal(cli.required[1].key, key) -- make sure it got added assert.is.error(function() cli:add_arg(key, desc) end) -- this should blow up end) it("tests add_flag() with a duplicate argument", function() -- takes: key, descr local key, desc, default = "--no-insert", "thedescription", nil cli:add_flag(key, desc, default) assert.are.equal(cli.optional[1].expanded_key, "no-insert") -- make sure it got added assert.is.error(function() cli:add_flag("--[no-]insert", desc) end) -- this should blow up end) it("tests add_opt() with a duplicate flag", function() -- takes: key, descr local key, desc, default = "-i, --[no-]insert", "thedescription", true cli:add_flag(key, desc, default) assert.are.equal(cli.optional[1].key, "i") -- make sure it got added assert.are.equal(cli.optional[1].expanded_key, "insert") -- make sure it got added assert.is.error(function() cli:add_opt("--no-insert", desc, '') end) -- this should blow up assert.is.error(function() cli:add_opt("--insert", desc, '') end) -- this should blow up end) it("tests add_opt() with a duplicate argument", function() -- takes: key, descr local key, desc, default = "-i", "thedescription", "default" cli:add_opt(key, desc, default) assert.are.equal(cli.optional[1].key, "i") -- make sure it got added assert.is.error(function() cli:add_opt(key, desc, default) end) -- this should blow up end) describe("testing the 'noprint' options", function() local old_print, touched setup(function() old_print = print local interceptor = function(...) touched = true return old_print(...) end print = interceptor end) teardown(function() print = (old_print or print) end) before_each(function() touched = nil end) after_each(function() end) it("tests whether print_help() does not print anything, if noprint is set (includes print_usage())", function() local key, desc, default = "-a", "thedescription", "default" local noprint = true cli:add_opt(key, desc, default) local res = cli:print_help(noprint) assert.is.equal(type(res), "string") assert.is.equal(nil, touched) end) it("tests whether a parsing error through cli_error() does not print anything, if noprint is set", function() -- generate a parse error local key, desc = "ARGUMENT", "thedescription" cli:add_opt(key, desc) local noprint = true local args = {"arg1", "arg2", "arg3", "arg4"} -- should fail for too many arguments local res, err = cli:parse(args, noprint) assert.is.equal(nil, res) assert.is.equal(type(err), "string") assert.is.equal(nil, touched) end) end) end) -- public functions end) lua_cliargs-2.5-4/spec/cliargs_parsing_spec.lua000066400000000000000000000417621260614211400216330ustar00rootroot00000000000000local cli, defaults, result -- some helper stuff for debugging local quoted = function(s) return "'" .. tostring(s) .. "'" end local dump = function(t) print(" ============= Dump " .. tostring(t) .. " =============") if type(t) ~= "table" then print(quoted(tostring(t))) else for k,v in pairs(t) do print(quoted(k),quoted(v)) end end print(" ============= Dump " .. tostring(t) .. " =============") end -- fixture local function populate_required() cli:add_argument("INPUT", "path to the input file") return { ["INPUT"] = nil } end local function populate_optarg(cnt) cnt = cnt or 1 cli:optarg("OUTPUT", "path to the output file", "./out", cnt) if cnt == 1 then return { OUTPUT = "./out" } else return { OUTPUT = {"./out"}} end end local function populate_optionals() cli:add_option("-c, --compress=FILTER", "the filter to use for compressing output: gzip, lzma, bzip2, or none", "gzip") cli:add_option("-o FILE", "path to output file", "/dev/stdout") return { c = "gzip", compress = "gzip", o = "/dev/stdout" } end local function populate_flags() cli:add_flag("-v, --version", "prints the program's version and exits") cli:add_flag("-d", "script will run in DEBUG mode") cli:add_flag("--verbose", "the script output will be very verbose") return { d = nil, v = nil, version = nil, verbose = nil } end -- start tests describe("Testing cliargs library parsing commandlines", function() setup(function() _G._TEST = true end) teardown(function() _G._TEST = nil end) before_each(function() _G.arg = nil package.loaded.cliargs = nil -- Busted uses it, but must force to reload cli = require("cliargs") end) it("tests no arguments set, nor provided", function() local args = {} local result = cli:parse(args) assert.are.same(result, {}) end) it("tests uses global arg if arguments set not passed in", function() _G.arg = { "--version" } local defaults = populate_flags(cli) defaults.v = true defaults.version = true local result = cli:parse(true --[[no print]]) assert.are.same(result, defaults) end) it("tests only optionals, nothing provided", function() local args = {} local defaults = populate_optionals(cli) local result = cli:parse(args) assert.are.same(result, defaults) end) it("tests only required, all provided", function() local args = { "some_file" } populate_required(cli) local result = cli:parse(args) assert.are.same(result, { ["INPUT"] = "some_file" }) end) it("tests only optionals, all provided", function() local args = { "-o", "/dev/cdrom", "--compress=lzma" } populate_optionals(cli) local result = cli:parse(args) assert.are.same(result, { o = "/dev/cdrom", c = "lzma", compress = "lzma" }) end) it("tests optionals + required, all provided", function() local args = { "-o", "/dev/cdrom", "-c", "lzma", "some_file" } populate_required(cli) populate_optionals(cli) local result = cli:parse(args) assert.are.same(result, { o = "/dev/cdrom", c = "lzma", compress = "lzma", ["INPUT"] = "some_file" }) end) it("tests optional using -short-key notation", function() local defaults = populate_optionals(cli) defaults.c = "lzma" defaults.compress = "lzma" local result = cli:parse({ "-c", "lzma" }) assert.are.same(result, defaults) end) it("tests option using -short-key value notation", function() _G.arg = { "-out", "outfile" } cli:add_opt("-out VALUE", "output file") local defaults = { out = "outfile" } local result = cli:parse() assert.are.same(result, defaults) end) it("tests optional using --expanded-key notation, --x=VALUE", function() local defaults = populate_optionals(cli) defaults.c = "lzma" defaults.compress = "lzma" local result = cli:parse({ "--compress=lzma" }) assert.are.same(result, defaults) end) it("tests optional using alternate --expanded-key notation, --x VALUE", function() local defaults = populate_optionals(cli) defaults.c = "lzma" defaults.compress = "lzma" local result = cli:parse({ "--compress", "lzma" }) assert.are.same(result, defaults) end) describe("no-flag", function() it("can set default to false for flag", function() cli:add_flag("-R, --[no-]recursive", "copy recursively", false) local expected = { R = false, recursive = false } local result = cli:parse({}) assert.are.same(expected, result) end) it("can set default to true for flag", function() cli:add_flag("-R, --[no-]recursive", "copy recursively", true) local expected = { R = true, recursive = true } local result = cli:parse({}) assert.are.same(expected, result) end) it("sets flag value to false", function() cli:add_flag("-k, --[no-]keep-going", "continue as much as possible after an error", true) local expected = { k = false, ['keep-going'] = false } local result = cli:parse({ "--no-keep-going" }) assert.are.same(expected, result) end) it("sets flag value true then overwrites to false", function() cli:add_flag("-k, --[no-]keep-going", "continue as much as possible after an error", true) local expected = { k = false, ['keep-going'] = false } local result = cli:parse({ "-k", "--no-keep-going" }) assert.are.same(expected, result) end) it("sets flag value false then overwrites to true", function() cli:add_flag("-k, --[no-]keep-going", "continue as much as possible after an error", true) local expected = { k = true, ['keep-going'] = true } local result = cli:parse({ "--no-keep-going", "--keep-going" }) assert.are.same(expected, result) end) end) describe("multiple values for a single key", function() it("should work for keys that explicitly permit it", function() cli:add_option("-k, --key=VALUE", "key that can be specified multiple times", {}) local defaults = { key = {"value1", "value2", "value3"} } defaults.k = defaults.key local result = cli:parse({ "--key", "value1", "-k", "value2", "--key=value3" }) assert.are.same(result, defaults) end) it("should bail if the default value is not an empty table", function() assert.is.error(function() cli:add_option("-k", "a key that can be specified multiple times", { "foo" }) end, "Default argument: expected a") end) it("should print [] as the default value in the --help listing", function() cli:add_option("-k, --key=VALUE", "key that can be specified multiple times", {}) local help_msg = cli:print_help(true) assert.is_true( nil ~= help_msg:match("key that can be specified multiple times %(default: %[%]%)") ) end) end) describe("flag options", function() it("should turn them on using the -short-key notation", function() local defaults = populate_flags(cli) defaults.v = true defaults.version = true local result = cli:parse({ "-v" }) assert.are.same(result, defaults) end) it("should turn them on using the --expanded-key notation", function() local defaults = populate_flags(cli) defaults.v = true defaults.version = true local result = cli:parse({ "--version" }) assert.are.same(result, defaults) end) describe("given a -short-key only flag option", function() it("works", function() cli:add_flag("-d", "script will run in DEBUG mode") local result = cli:parse({ "-d" }) assert.are.same(result, { d = true }) end) end) describe("given an --expanded-key only flag option", function() it("works", function() local defaults = populate_flags(cli) defaults.verbose = true result = cli:parse({ "--verbose" }) assert.are.same(result, defaults) end) end) describe("given a value for a flag", function() it("bails", function() local defaults = populate_flags(cli) defaults.verbose = true local result, err = cli:parse({ "--verbose=something" }, true --[[no print]]) assert(result == nil, "Adding a value to a flag must error out") assert(type(err) == "string", "Expected an error string") end) end) end) it("tests optionals + required, no optionals and to little required provided, ", function() populate_required(cli) populate_optionals(cli) local result = cli:parse({}, true --[[no print]]) assert.is.falsy(result) end) it("tests optionals + required, no optionals and too many required provided, ", function() populate_required(cli) populate_optionals(cli) local result = cli:parse({ "some_file", "some_other_file" }, true --[[no print]]) assert.is.falsy(result) end) it("tests optionals + required + optarg, '--' as end of optionals", function() populate_required(cli) populate_optarg(1) local expected = populate_flags(cli) expected.INPUT = "--input" expected.OUTPUT = "-d" expected.verbose = true local result = cli:parse({ "--verbose", "--", "--input", "-d" }) assert.is.same(expected, result) end) it("tests bad short-key notation, -x=VALUE", function() populate_optionals(cli) local result = cli:parse({ "-o=some_file" }, true --[[no print]]) assert.is.falsy(result) end) it("tests unknown option", function() populate_optionals(cli) local result = cli:parse({ "--foo=bar" }, true --[[no print]]) assert.is.falsy(result) end) it("tests unknown flag", function() populate_optionals(cli) local result = cli:parse({ "--foo" }, true --[[no print]]) assert.is.falsy(result) end) it("tests optarg only, defaults, multiple allowed", function() defaults = populate_optarg(3) local result,err = cli:parse(true --[[no print]]) assert.is.same(defaults, result) end) it("tests optarg only, defaults, 1 allowed", function() defaults = populate_optarg(1) local result = cli:parse(true --[[no print]]) assert.is.same(defaults, result) end) it("tests optarg only, values, multiple allowed", function() defaults = populate_optarg(3) local result = cli:parse({"/output1/", "/output2/"}, true --[[no print]]) assert.is.same(result, { OUTPUT = {"/output1/", "/output2/"}}) end) it("tests optarg only, values, 1 allowed", function() local defaults = populate_optarg(1) local result = cli:parse({"/output/"}, true --[[no print]]) assert.is.same(result, { OUTPUT = "/output/" }) end) it("tests optarg only, too many values", function() local defaults = populate_optarg(1) local result = cli:parse({"/output1/", "/output2/"}, true --[[no print]]) assert.is.same(result, nil) end) it("tests optarg only, too many values", function() populate_required() populate_optarg(1) local result = cli:parse({"/input/", "/output/"}, true --[[no print]]) assert.is.same(result, { INPUT = "/input/", OUTPUT = "/output/" }) end) it("tests clearing the default of an optional", function() populate_optionals(cli) local result, err = cli:parse({ "--compress=" }, true --[[no print]]) assert.are.equal(nil,err) -- are_not.equal is not working when comparing against a nil as -- of luassert-1.2-1, using is.truthy instead for now -- assert.are_not.equal(nil,result) assert.is.truthy(result) assert.are.equal("", result.compress) end) describe("Tests options parsing with callback", function() local cb = {} local function callback(key, value, altkey, opt) cb.key, cb.value, cb.altkey = key, value, altkey return true end local function callback_fail(key, value, altkey, opt) return nil, "bad argument to " .. opt end before_each(function() cb = {} end) it("tests short-key option", function() cli:add_option("-k, --long-key=VALUE", "key description", "", callback) local expected = { k = "myvalue", ["long-key"] = "myvalue" } local result = cli:parse({ "-k", "myvalue" }) assert.are.same(expected, result) assert.are.equal("k", cb.key) assert.are.equal("myvalue", cb.value) assert.are.equal("long-key", cb.altkey) end) it("tests expanded-key option", function() cli:add_option("-k, --long-key=VALUE", "key description", "", callback) local expected = { k = "val", ["long-key"] = "val" } local result = cli:parse({ "--long-key", "val" }) assert.are.same(expected, result) assert.are.equal("long-key", cb.key) assert.are.equal("val", cb.value) assert.are.equal("k", cb.altkey) end) it("tests expanded-key flag with not short-key", function() cli:add_flag("--version", "prints the version and exits", callback) local expected = { version = true } local result = cli:parse({ "--version" }) assert.are.same(expected, result) assert.are.equal("version", cb.key) assert.are.equal(true, cb.value) assert.are.equal(nil, cb.altkey) end) it("tests callback for no-flags", function() cli:add_flag("-k, --[no-]long-key", "key description", callback) local expected = { k = false, ["long-key"] = false } local result = cli:parse({ "--no-long-key" }) assert.are.same(expected, result) assert.are.equal("long-key", cb.key) assert.are.equal(false, cb.value) assert.are.equal("k", cb.altkey) end) it("tests callback returning error", function() cli:set_name('myapp') cli:add_option("-k, --long-key=VALUE", "key description", "", callback_fail) local result, err = cli:parse({ "--long-key", "val" }, true --[[no print]]) assert(result == nil, "Failure in callback returns nil") assert(type(err) == "string", "Expected an error string") assert.are.equal(err, "myapp: error: bad argument to --long-key; re-run with --help for usage.") end) end) describe("Tests argument parsing with callback", function() local cb = {} local function callback(key, value) cb.key, cb.value = key, value return true end local function callback_arg(key, value) table.insert(cb, { key = key, value = value }) return true end local function callback_fail(key, value) return nil, "bad argument for " .. key end before_each(function() cb = {} end) it("tests one required argument", function() cli:add_arg("ARG", "arg description", callback) local expected = { ARG = "arg_val" } local result = cli:parse({ "arg_val" }) assert.are.same(expected, result) assert.are.equal("ARG", cb.key) assert.are.equal("arg_val", cb.value) end) it("tests required argument callback returning error", function() cli:set_name('myapp') cli:add_arg("ARG", "arg description", callback_fail) local expected = { ARG = "arg_val" } local result, err = cli:parse({ "arg_val" }, true --[[no print]]) assert(result == nil, "Failure in callback returns nil") assert(type(err) == "string", "Expected an error string") assert.are.equal(err, "myapp: error: bad argument for ARG; re-run with --help for usage.") end) it("tests many required arguments", function() cli:add_arg("ARG1", "arg1 description", callback_arg) cli:add_arg("ARG2", "arg2 description", callback_arg) cli:add_arg("ARG3", "arg3 description", callback_arg) local expected = { ARG1 = "arg1_val", ARG2 = "arg2_val", ARG3 = "arg3_val" } local result = cli:parse({ "arg1_val", "arg2_val", "arg3_val" }) assert.are.same(expected, result) assert.are.same({ key = "ARG1", value = "arg1_val"}, cb[1]) assert.are.same({ key = "ARG2", value = "arg2_val"}, cb[2]) assert.are.same({ key = "ARG3", value = "arg3_val"}, cb[3]) end) it("tests one optional argument", function() cli:optarg("OPTARG", "optional arg description", nil, 1, callback) local expected = { OPTARG = "opt_arg" } local result = cli:parse({ "opt_arg" }) assert.are.same(expected, result) assert.are.equal("OPTARG", cb.key) assert.are.equal("opt_arg", cb.value) end) it("tests optional argument callback returning error", function() cli:set_name('myapp') cli:optarg("OPTARG", "optinoal arg description", nil, 1, callback_fail) local expected = { ARG = "arg_val" } local result, err = cli:parse({ "opt_arg" }, true --[[no print]]) assert(result == nil, "Failure in callback returns nil") assert(type(err) == "string", "Expected an error string") assert.are.equal(err, "myapp: error: bad argument for OPTARG; re-run with --help for usage.") end) it("tests many optional arguments", function() cli:optarg("OPTARG", "optional arg description", nil, 3, callback_arg) local expected = { OPTARG = { "opt_arg1", "opt_arg2", "opt_arg3" } } local result = cli:parse({ "opt_arg1", "opt_arg2", "opt_arg3" }) assert.are.same(expected, result) assert.are.same({ key = "OPTARG", value = "opt_arg1"}, cb[1]) assert.are.same({ key = "OPTARG", value = "opt_arg2"}, cb[2]) assert.are.same({ key = "OPTARG", value = "opt_arg3"}, cb[3]) end) end) end) lua_cliargs-2.5-4/src/000077500000000000000000000000001260614211400145725ustar00rootroot00000000000000lua_cliargs-2.5-4/src/cliargs.lua000066400000000000000000000541451260614211400167320ustar00rootroot00000000000000local cli, _ -- ------- -- -- Helpers -- -- ------- -- local split = function(str, pat) local t = {} local fpat = "(.-)" .. pat local last_end = 1 local s, e, cap = str:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(t,cap) end last_end = e+1 s, e, cap = str:find(fpat, last_end) end if last_end <= #str then cap = str:sub(last_end) table.insert(t, cap) end return t end local buildline = function(words, size, overflow) -- if overflow is set, a word longer than size, will overflow the size -- otherwise it will be chopped in line-length pieces local line = "" if string.len(words[1]) > size then -- word longer than line if overflow then line = words[1] table.remove(words, 1) else line = words[1]:sub(1, size) words[1] = words[1]:sub(size + 1, -1) end else while words[1] and (#line + string.len(words[1]) + 1 <= size) or (line == "" and #words[1] == size) do if line == "" then line = words[1] else line = line .. " " .. words[1] end table.remove(words, 1) end end return line, words end local wordwrap = function(str, size, pad, overflow) -- if overflow is set, then words longer than a line will overflow -- otherwise, they'll be chopped in pieces pad = pad or 0 local line = "" local out = "" local padstr = string.rep(" ", pad) local words = split(str, ' ') while words[1] do line, words = buildline(words, size, overflow) if out == "" then out = padstr .. line else out = out .. "\n" .. padstr .. line end end return out end local function disect(key) -- characters allowed are a-z, A-Z, 0-9 -- extended + values also allow; # @ _ + - local k, ek, v local dummy -- if there is no comma, between short and extended, add one _, _, dummy = key:find("^%-([%a%d]+)[%s]%-%-") if dummy then key = key:gsub("^%-[%a%d][%s]%-%-", "-"..dummy..", --", 1) end -- for a short key + value, replace space by "=" _, _, dummy = key:find("^%-([%a%d]+)[%s]") if dummy then key = key:gsub("^%-([%a%d]+)[ ]", "-"..dummy.."=", 1) end -- if there is no "=", then append one if not key:find("=") then key = key .. "=" end -- get value _, _, v = key:find(".-%=(.+)") -- get key(s), remove spaces key = split(key, "=")[1]:gsub(" ", "") -- get short key & extended key _, _, k = key:find("^%-([^-][^%s,]*)") _, _, ek = key:find("%-%-(.+)$") if v == "" then v = nil end return k,ek,v end local function callable(fn) return type(fn) == "function" or (getmetatable(fn) or {}).__call end function cli_error(msg, noprint) local msg = cli.name .. ": error: " .. msg .. '; re-run with --help for usage.' if not noprint then print(msg) end return nil, msg end -- -------- -- -- CLI Main -- -- -------- -- cli = { name = "", required = {}, optional = {}, optargument = {maxcount = 0}, colsz = { 0, 0 }, -- column width, help text. Set to 0 for auto detect maxlabel = 0, } --- Assigns the name of the program which will be used for logging. function cli:set_name(name) self.name = name end -- Used internally to lookup an entry using either its short or expanded keys function cli:__lookup(k, ek, t) t = t or self.optional local _ for _,entry in ipairs(t) do if k and entry.key == k then return entry end if ek and entry.expanded_key == ek then return entry end if entry.has_no_flag then if ek and ("no-"..entry.expanded_key) == ek then return entry end end end return nil end --- Defines a required argument. --- Required arguments have no special notation and are order-sensitive. --- *Note:* the value will be stored in `args[@key]`. --- *Aliases: `add_argument`* --- --- ### Parameters --- 1. **key**: the argument's "name" that will be displayed to the user --- 2. **desc**: a description of the argument --- 3. **callback**: *optional*; specify a function to call when this argument is parsed (the default is nil) --- --- ### Usage example --- The following will parse the argument (if specified) and set its value in `args["root"]`: --- `cli:add_arg("root", "path to where root scripts can be found")` function cli:add_arg(key, desc, callback) assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)") assert(callable(callback) or callback == nil, "Callback argument: expected a function or nil") if self:__lookup(key, nil, self.required) then error("Duplicate argument: " .. key .. ", please rename one of them.") end table.insert(self.required, { key = key, desc = desc, value = nil, callback = callback }) if #key > self.maxlabel then self.maxlabel = #key end end --- Defines an optional argument (or more than one). --- There can be only 1 optional argument, and it has to be the last one on the argumentlist. --- *Note:* the value will be stored in `args[@key]`. The value will be a 'string' if 'maxcount == 1', --- or a table if 'maxcount > 1' --- --- ### Parameters --- 1. **key**: the argument's "name" that will be displayed to the user --- 2. **desc**: a description of the argument --- 3. **default**: *optional*; specify a default value (the default is nil) --- 4. **maxcount**: *optional*; specify the maximum number of occurences allowed (default is 1) --- 5. **callback**: *optional*; specify a function to call when this argument is parsed (the default is nil) --- --- ### Usage example --- The following will parse the argument (if specified) and set its value in `args["root"]`: --- `cli:add_arg("root", "path to where root scripts can be found", "", 2)` --- The value returned will be a table with at least 1 entry and a maximum of 2 entries function cli:optarg(key, desc, default, maxcount, callback) assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)") assert(type(default) == "string" or default == nil, "Default value must either be omitted or be a string") maxcount = maxcount or 1 maxcount = tonumber(maxcount) assert(maxcount and maxcount>0 and maxcount<1000,"Maxcount must be a number from 1 to 999") assert(callable(callback) or callback == nil, "Callback argument: expected a function or nil") self.optargument = { key = key, desc = desc, default = default, maxcount = maxcount, value = nil, callback = callback } if #key > self.maxlabel then self.maxlabel = #key end end -- Used internally to add an option function cli:__add_opt(k, ek, v, label, desc, default, callback) local flag = (v == nil) -- no value, so it's a flag local has_no_flag = flag and (ek and ek:find('^%[no%-]') ~= nil) local ek = has_no_flag and ek:sub(6) or ek -- guard against duplicates if self:__lookup(k, ek) then error("Duplicate option: " .. (k or ek) .. ", please rename one of them.") end if has_no_flag and self:__lookup(nil, "no-"..ek) then error("Duplicate option: " .. ("no-"..ek) .. ", please rename one of them.") end -- below description of full entry record, nils included for reference local entry = { key = k, expanded_key = ek, desc = desc, default = default, label = label, flag = flag, has_no_flag = has_no_flag, value = default, callback = callback, } table.insert(self.optional, entry) if #label > self.maxlabel then self.maxlabel = #label end end --- Defines an option. --- Optional arguments can use 3 different notations, and can accept a value. --- *Aliases: `add_option`* --- --- ### Parameters --- 1. **key**: the argument identifier, can be either `-key`, or `-key, --expanded-key`: --- if the first notation is used then a value can be defined after a space (`'-key VALUE'`), --- if the 2nd notation is used then a value can be defined after an `=` (`'-key, --expanded-key=VALUE'`). --- As a final option it is possible to only use the expanded key (eg. `'--expanded-key'`) both with and --- without a value specified. --- 2. **desc**: a description for the argument to be shown in --help --- 3. **default**: *optional*; specify a default value (the default is nil) --- 4. **callback**: *optional*; specify a function to call when this option is parsed (the default is nil) --- --- ### Usage example --- The following option will be stored in `args["i"]` and `args["input"]` with a default value of `my_file.txt`: --- `cli:add_option("-i, --input=FILE", "path to the input file", "my_file.txt")` function cli:add_opt(key, desc, default, callback) -- parameterize the key if needed, possible variations: -- 1. -key -- 2. -key VALUE -- 3. -key, --expanded -- 4. -key, --expanded=VALUE -- 5. -key --expanded -- 6. -key --expanded=VALUE -- 7. --expanded -- 8. --expanded=VALUE assert(type(key) == "string" and type(desc) == "string", "Key and description are mandatory arguments (Strings)") assert(callable(callback) or callback == nil, "Callback argument: expected a function or nil") assert( ( type(default) == "string" or default == nil or type(default) == "boolean" or (type(default) == "table" and next(default) == nil) ), "Default argument: expected a string, nil, or {}" ) local k, ek, v = disect(key) -- set defaults if v == nil and type(default) ~= "boolean" then default = nil end self:__add_opt(k, ek, v, key, desc, default, callback) end --- Define a flag argument (on/off). This is a convenience helper for cli.add_opt(). --- See cli.add_opt() for more information. --- --- ### Parameters -- 1. **key**: the argument's key -- 2. **desc**: a description of the argument to be displayed in the help listing -- 3. **default**: *optional*; specify a default value (the default is nil) -- 4. **callback**: *optional*; specify a function to call when this flag is parsed (the default is nil) function cli:add_flag(key, desc, default, callback) if type(default) == "function" then callback = default default = nil end assert(default == nil or type(default) == "boolean", "Default argument: expected a boolean, nil") local k, ek, v = disect(key) if v ~= nil then error("A flag type option cannot have a value set: " .. key) end self:__add_opt(k, ek, nil, key, desc, default, callback) end --- Parses the arguments found in #arg and returns a table with the populated values. --- (NOTE: after succesful parsing, the module will delete itself to free resources) --- *Aliases: `parse_args`* --- --- ### Parameters --- 1. **arguments**: set this to arg --- 2. **noprint**: set this flag to prevent any information (error or help info) from being printed --- 3. **dump**: set this flag to dump the parsed variables for debugging purposes, alternatively --- set the first option to --__DUMP__ (option with 2 trailing and leading underscores) to dump at runtime. --- --- ### Returns --- 1. a table containing the keys specified when the arguments were defined along with the parsed values, --- or nil + error message (--help option is considered an error and returns nil + help message) function cli:parse(arguments, noprint, dump) if type(arguments) ~= "table" then -- optional 'arguments' was not provided, so shift remaining arguments noprint, dump, arguments = arguments, noprint, nil end local arguments = arguments or arg or {} local args = {} for k,v in pairs(arguments) do args[k] = v end -- copy args local -- starts with --help? display the help listing and abort! if args[1] and (args[1] == "--help" or args[1] == "-h") then return nil, self:print_help(noprint) end -- starts with --__DUMP__; set dump to true to dump the parsed arguments if dump == nil then if args[1] and args[1] == "--__DUMP__" then dump = true table.remove(args, 1) -- delete it to prevent further parsing end end while args[1] do local entry = nil local opt = args[1] local _, optpref, optkey, optkey2, optval _, _, optpref, optkey = opt:find("^(%-[%-]?)(.+)") -- split PREFIX & NAME+VALUE if optkey then _, _, optkey2, optval = optkey:find("(.-)[=](.+)") -- split value and key if optval then optkey = optkey2 end end if not optpref then break -- no optional prefix, so options are done end if opt == "--" then table.remove(args, 1) break -- end of options end if optkey:sub(-1,-1) == "=" then -- check on a blank value eg. --insert= optval = "" optkey = optkey:sub(1,-2) end if optkey then entry = self:__lookup(optpref == '-' and optkey or nil, optpref == '--' and optkey or nil) end if not optkey or not entry then local option_type = optval and "option" or "flag" return cli_error("unknown/bad " .. option_type .. ": " .. opt, noprint) end table.remove(args,1) if optpref == "-" then if optval then return cli_error("short option does not allow value through '=': "..opt, noprint) end if entry.flag then optval = true else -- not a flag, value is in the next argument optval = args[1] table.remove(args, 1) end elseif optpref == "--" then -- using the expanded-key notation entry = self:__lookup(nil, optkey) if entry then if entry.flag then if optval then return cli_error("flag --" .. optkey .. " does not take a value", noprint) else optval = not entry.has_no_flag or (optkey:sub(1,3) ~= "no-") end else if not optval then -- value is in the next argument optval = args[1] table.remove(args, 1) end end else return cli_error("unknown/bad flag: " .. opt, noprint) end end if type(entry.value) == 'table' then table.insert(entry.value, optval) else entry.value = optval end -- invoke the option's parse-callback, if any if entry.callback then local altkey = entry.key if optkey == entry.key then altkey = entry.expanded_key else optkey = entry.expanded_key end local status, err = entry.callback(optkey, optval, altkey, opt) if status == nil and err then return cli_error(err, noprint) end end end -- missing any required arguments, or too many? if #args < #self.required or #args > #self.required + self.optargument.maxcount then if self.optargument.maxcount > 0 then return cli_error("bad number of arguments: " .. #self.required .."-" .. #self.required + self.optargument.maxcount .. " argument(s) must be specified, not " .. #args, noprint) else return cli_error("bad number of arguments: " .. #self.required .. " argument(s) must be specified, not " .. #args, noprint) end end -- deal with required args here for i, entry in ipairs(self.required) do entry.value = args[1] if entry.callback then local status, err = entry.callback(entry.key, entry.value) if status == nil and err then return cli_error(err, noprint) end end table.remove(args, 1) end -- deal with the last optional argument while args[1] do if self.optargument.maxcount > 1 then self.optargument.value = self.optargument.value or {} table.insert(self.optargument.value, args[1]) else self.optargument.value = args[1] end if self.optargument.callback then local status, err = self.optargument.callback(self.optargument.key, args[1]) if status == nil and err then return cli_error(err, noprint) end end table.remove(args,1) end -- if necessary set the defaults for the last optional argument here if self.optargument.maxcount > 0 and not self.optargument.value then if self.optargument.maxcount == 1 then self.optargument.value = self.optargument.default else self.optargument.value = { self.optargument.default } end end -- populate the results table local results = {} if self.optargument.maxcount > 0 then results[self.optargument.key] = self.optargument.value end for _, entry in pairs(self.required) do results[entry.key] = entry.value end for _, entry in pairs(self.optional) do if entry.key then results[entry.key] = entry.value end if entry.expanded_key then results[entry.expanded_key] = entry.value end end if dump then print("\n======= Provided command line =============") print("\nNumber of arguments: ", #arg) for i,v in ipairs(arg) do -- use gloabl 'arg' not the modified local 'args' print(string.format("%3i = '%s'", i, v)) end print("\n======= Parsed command line ===============") if #self.required > 0 then print("\nArguments:") end for i,v in ipairs(self.required) do print(" " .. v.key .. string.rep(" ", self.maxlabel + 2 - #v.key) .. " => '" .. v.value .. "'") end if self.optargument.maxcount > 0 then print("\nOptional arguments:") print(" " .. self.optargument.key .. "; allowed are " .. tostring(self.optargument.maxcount) .. " arguments") if self.optargument.maxcount == 1 then print(" " .. self.optargument.key .. string.rep(" ", self.maxlabel + 2 - #self.optargument.key) .. " => '" .. self.optargument.key .. "'") else for i = 1, self.optargument.maxcount do if self.optargument.value[i] then print(" " .. tostring(i) .. string.rep(" ", self.maxlabel + 2 - #tostring(i)) .. " => '" .. tostring(self.optargument.value[i]) .. "'") end end end end if #self.optional > 0 then print("\nOptional parameters:") end local doubles = {} for _, v in pairs(self.optional) do if not doubles[v] then local m = v.value if type(m) == "string" then m = "'"..m.."'" else m = tostring(m) .." (" .. type(m) .. ")" end print(" " .. v.label .. string.rep(" ", self.maxlabel + 2 - #v.label) .. " => " .. m) doubles[v] = v end end print("\n===========================================\n\n") return cli_error("commandline dump created as requested per '--__DUMP__' option", noprint) end if not _TEST then -- cleanup entire module, as it's single use -- remove from package.loaded table to enable the module to -- garbage collected. for k, v in pairs(package.loaded) do if v == cli then package.loaded[k] = nil break end end -- clear table in case user holds on to module table for k, _ in pairs(cli) do cli[k] = nil end end return results end --- Prints the USAGE heading. --- --- ### Parameters ---1. **noprint**: set this flag to prevent the line from being printed --- --- ### Returns --- 1. a string with the USAGE message. function cli:print_usage(noprint) -- print the USAGE heading local msg = "Usage: " .. tostring(self.name) if #self.optional > 0 then msg = msg .. " [OPTIONS]" end if #self.required > 0 or self.optargument.maxcount > 0 then msg = msg .. " [--]" end if #self.required > 0 then for _,entry in ipairs(self.required) do msg = msg .. " " .. entry.key end end if self.optargument.maxcount == 1 then msg = msg .. " [" .. self.optargument.key .. "]" elseif self.optargument.maxcount == 2 then msg = msg .. " [" .. self.optargument.key .. "-1 [" .. self.optargument.key .. "-2]]" elseif self.optargument.maxcount > 2 then msg = msg .. " [" .. self.optargument.key .. "-1 [" .. self.optargument.key .. "-2 [...]]]" end if not noprint then print(msg) end return msg end --- Prints the HELP information. --- --- ### Parameters --- 1. **noprint**: set this flag to prevent the information from being printed --- --- ### Returns --- 1. a string with the HELP message. function cli:print_help(noprint) local msg = self:print_usage(true) .. "\n" local col1 = self.colsz[1] local col2 = self.colsz[2] if col1 == 0 then col1 = cli.maxlabel end col1 = col1 + 3 --add margins if col2 == 0 then col2 = 72 - col1 end if col2 <10 then col2 = 10 end local append = function(label, desc) label = " " .. label .. string.rep(" ", col1 - (#label + 2)) desc = wordwrap(desc, col2) -- word-wrap desc = desc:gsub("\n", "\n" .. string.rep(" ", col1)) -- add padding msg = msg .. label .. desc .. "\n" end if self.required[1] then msg = msg .. "\nARGUMENTS: \n" for _,entry in ipairs(self.required) do append(entry.key, entry.desc .. " (required)") end end if self.optargument.maxcount > 0 then append(self.optargument.key, self.optargument.desc .. " (optional, default: " .. self.optargument.default .. ")") end if #self.optional > 0 then msg = msg .. "\nOPTIONS: \n" for _,entry in ipairs(self.optional) do local desc = entry.desc if not entry.flag and entry.default and #tostring(entry.default) > 0 then local readable_default = type(entry.default) == "table" and "[]" or tostring(entry.default) desc = desc .. " (default: " .. readable_default .. ")" elseif entry.flag and entry.has_no_flag then local readable_default = entry.default and 'on' or 'off' desc = desc .. " (default: " .. readable_default .. ")" end append(entry.label, desc) end end if not noprint then print(msg) end return msg end --- Sets the amount of space allocated to the argument keys and descriptions in the help listing. --- The sizes are used for wrapping long argument keys and descriptions. --- ### Parameters --- 1. **key_cols**: the number of columns assigned to the argument keys, set to 0 to auto detect (default: 0) --- 1. **desc_cols**: the number of columns assigned to the argument descriptions, set to 0 to auto set the total width to 72 (default: 0) function cli:set_colsz(key_cols, desc_cols) self.colsz = { key_cols or self.colsz[1], desc_cols or self.colsz[2] } end -- finalize setup cli._COPYRIGHT = "Copyright (C) 2011-2014 Ahmad Amireh" cli._LICENSE = "The code is released under the MIT terms. Feel free to use it in both open and closed software as you please." cli._DESCRIPTION = "Commandline argument parser for Lua" cli._VERSION = "cliargs 2.5-4" -- aliases cli.add_argument = cli.add_arg cli.add_option = cli.add_opt cli.parse_args = cli.parse -- backward compatibility -- test aliases for local functions if _TEST then cli.split = split cli.wordwrap = wordwrap end return cli