1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-30 20:53:52 +00:00

Merge branch 'master' into basic-enum

This commit is contained in:
Henry Schreiner 2017-06-09 08:30:44 -04:00 committed by GitHub
commit 00e0506f53
6 changed files with 46 additions and 19 deletions

View File

@ -1,7 +1,10 @@
## Version 1.1 (in progress)
* Added support for basic enumerations [#12](https://github.com/CLIUtils/CLI11/issues/12)
* Added `app.parse_order()` with original parse order
* Added `prefix_command()`, which is like `allow_extras` but instantly stops and returns.
* Added simple support for enumerations, allow non-printable objects [#12](https://github.com/CLIUtils/CLI11/issues/12)
* Added `app.parse_order()` with original parse order ([#13](https://github.com/CLIUtils/CLI11/issues/13), [#16](https://github.com/CLIUtils/CLI11/pull/16))
* Added `prefix_command()`, which is like `allow_extras` but instantly stops and returns. ([#8](https://github.com/CLIUtils/CLI11/issues/8), [#17](https://github.com/CLIUtils/CLI11/pull/17))
* Removed Windows error ([#10](https://github.com/CLIUtils/CLI11/issues/10), [#20](https://github.com/CLIUtils/CLI11/pull/20))
* Some improvements to CMake, detect Python and no dependencies on Python 2 (like Python 3) ([#18](https://github.com/CLIUtils/CLI11/issues/18), [#21](https://github.com/CLIUtils/CLI11/pull/21))
## Version 1.0
* Cleanup using `clang-tidy` and `clang-format`

View File

@ -13,7 +13,6 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
# Be moderately paranoid with flags
if(MSVC)
add_definitions("/W4")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
else()
add_definitions("-Wall -Wextra -pedantic")
endif()
@ -54,11 +53,18 @@ add_library(CLI11 INTERFACE)
target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Single file test
option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CUR_PROJ})
find_package(PythonInterp)
if(CUR_PROJ AND PYTHONINTERP_FOUND)
set(CLI_SINGLE_FILE_DEFAULT ON)
else()
set(CLI_SINGLE_FILE_DEFAULT OFF)
endif()
option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CLI_SINGLE_FILE_DEFAULT})
if(CLI_SINGLE_FILE)
find_package(PythonInterp REQUIRED)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
COMMAND python "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI_headers}
)
add_custom_target(generate_cli_single_file ALL

View File

@ -10,7 +10,7 @@
CLI11 provides all the features you expect in a powerful command line parser, with a beautiful, minimal syntax and no dependencies beyond C++11. It is header only, and comes in a single file form for easy inclusion in projects. It is easy to use for small projects, but powerful enough for complex command line projects, and can be customized for frameworks.
It is tested on [Travis] and [AppVeyor], and is being included in the [GooFit GPU fitting framework][GooFit]. It was inspired by [`plumbum.cli`][Plumbum] for Python. CLI11 has a user friendly introduction in this README, a more indepth tutorial [GitBook], as well as [API documentation][api-docs] generated by Travis.
See the [changelog](./CHANGELOG.md) or [GitHub Releases] for details for current and past releases. The 1.0 announcement post can be found [here](http://iscinumpy.blogspot.com/2017/06/announcing-cli11-version-10.html).
See the [changelog](./CHANGELOG.md) or [GitHub Releases] for details for current and past releases. The version 1.0 announcement post can be found [here](http://iscinumpy.blogspot.com/2017/06/announcing-cli11-version-10.html).
### Why write another CLI parser?
@ -126,7 +126,7 @@ app.add_set_ignore_case(... // String only
App* subcom = app.add_subcommand(name, discription);
```
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`. The set options allow your users to pick from a set of predefined options.
### Example

View File

@ -46,6 +46,8 @@ gtest_build_tests
gtest_disable_pthreads
gtest_force_shared_crt
gtest_hide_internal_symbols
BUILD_GMOCK
BUILD_GTEST
)
set_target_properties(gtest gtest_main gmock gmock_main

View File

@ -909,9 +909,25 @@ class App {
// Get envname options if not yet passed
for(const Option_p &opt : options_) {
if(opt->count() == 0 && opt->envname_ != "") {
char *ename = std::getenv(opt->envname_.c_str());
if(ename != nullptr) {
opt->add_result(std::string(ename));
char *buffer = nullptr;
std::string ename_string;
#ifdef _MSC_VER
// Windows version
size_t sz = 0;
if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
ename_string = std::string(buffer);
free(buffer);
}
#else
// This also works on Windows, but gives a warning
buffer = std::getenv(opt->envname_.c_str());
if(buffer != nullptr)
ename_string = std::string(buffer);
#endif
if(!ename_string.empty()) {
opt->add_result(ename_string);
}
}
}

View File

@ -4,24 +4,24 @@
from __future__ import print_function, unicode_literals
import os
import re
import argparse
from pathlib import Path
from subprocess import check_output
includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE)
includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE)
DIR = Path(__file__).resolve().parent
BDIR = DIR.parent / 'include'
DIR = os.path.dirname(os.path.abspath(__file__)) # Path(__file__).resolve().parent
BDIR = os.path.join(os.path.dirname(DIR), 'include') # DIR.parent / 'include'
print("Git directory:", DIR)
TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8")
def MakeHeader(out):
main_header = BDIR / 'CLI/CLI.hpp'
with main_header.open() as f:
main_header = os.path.join(BDIR, 'CLI', 'CLI.hpp')
with open(main_header) as f:
header = f.read()
include_files = includes_local.findall(header)
@ -29,7 +29,7 @@ def MakeHeader(out):
headers = set()
output = ''
for inc in include_files:
with (BDIR / inc).open() as f:
with open(os.path.join(BDIR, inc)) as f:
inner = f.read()
headers |= set(includes_system.findall(inner))
output += '\n// From {inc}\n\n'.format(inc=inc)
@ -50,7 +50,7 @@ def MakeHeader(out):
{header_list}
{output}'''.format(header_list=header_list, output=output, tag=TAG)
with Path(out).open('w') as f:
with open(out, 'w') as f:
f.write(output)
print("Created {out}".format(out=out))
@ -58,6 +58,6 @@ def MakeHeader(out):
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("output", nargs='?', default=BDIR / 'CLI11.hpp')
parser.add_argument("output", nargs='?', default=os.path.join(BDIR, 'CLI11.hpp'))
args = parser.parse_args()
MakeHeader(args.output)