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

Travis improvements and updates (#28)

* Adding check for style

* Adding reformats

* Fix syntax error in travis

* Support clang-format 3.9

* Adding clang-tidy check
This commit is contained in:
Henry Schreiner 2017-09-01 16:51:09 -04:00 committed by GitHub
parent b88f1f2ac7
commit 54114d0948
11 changed files with 97 additions and 96 deletions

17
.ci/check_style.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env sh
set -evx
clang-format --version
git ls-files -- '*.cpp' '*.hpp' | xargs clang-format -i -style=file
git diff --exit-code --color
mkdir build || true
cd build
CXX_FLAGS="-Werror -Wall -Wextra -pedantic -std=c++11" cmake .. -DCLANG_TIDY_FIX=ON
cmake --build .
git diff --exit-code --color
set +evx

View File

@ -9,6 +9,8 @@ if [ "$CXX" = "g++" ] ; then
else else
ln -s `which clang-$COMPILER` clang ln -s `which clang-$COMPILER` clang
ln -s `which clang++-$COMPILER` clang++ ln -s `which clang++-$COMPILER` clang++
ln -s `which clang-format-$COMPILER` clang-format
ln -s `which clang-tidy-$COMPILER` clang-tidy
fi fi
export PATH="${DEPS_DIR}/extrabin":$PATH export PATH="${DEPS_DIR}/extrabin":$PATH

View File

@ -6,3 +6,5 @@ cd build
cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build . -- -j2 cmake --build . -- -j2
ctest --output-on-failure ctest --output-on-failure
set +evx

View File

@ -13,9 +13,16 @@ matrix:
- compiler: clang - compiler: clang
addons: addons:
apt: apt:
sources: packages:
- llvm-toolchain-precise-3.5 - clang-3.9
- ubuntu-toolchain-r-test - clang-format-3.9
- clang-tidy-3.9
env:
- COMPILER=3.9
- CHECK_STYLE=yes
- compiler: clang
addons:
apt:
packages: packages:
- clang-3.5 - clang-3.5
env: env:
@ -37,8 +44,6 @@ matrix:
- compiler: gcc - compiler: gcc
addons: addons:
apt: apt:
sources:
- ubuntu-toolchain-r-test
packages: packages:
- g++-4.7 - g++-4.7
env: env:
@ -48,19 +53,21 @@ matrix:
install: install:
- python -c 'import sys; print(sys.version_info[:])' - python -c 'import sys; print(sys.version_info[:])'
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd $TRAVIS_BUILD_DIR && . .ci/prepare_altern.sh - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd $TRAVIS_BUILD_DIR && . .ci/prepare_altern.sh ; fi
; fi - if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_cmake.sh ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_cmake.sh - if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_doxygen.sh ; fi
; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_doxygen.sh
; fi
- if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_lcov.sh ; fi - if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_lcov.sh ; fi
- cd "${DEPS_DIR}" - cd "${DEPS_DIR}"
- if [ "$(python -c 'import sys; print(sys.version_info[0])')" = "2" ] ; then pip - if [ "$(python -c 'import sys; print(sys.version_info[0])')" = "2" ] ; then pip install --user pathlib ; fi
install --user pathlib; fi
script: script:
- cd "${TRAVIS_BUILD_DIR}" - cd "${TRAVIS_BUILD_DIR}"
- .ci/travis.sh - |
if [ -n "$CHECK_STYLE" ]
then
.ci/check_style.sh
else
.ci/travis.sh
fi
after_success: after_success:
- if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && .ci/run_codecov.sh ; fi - if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && .ci/run_codecov.sh ; fi
- echo "${TRAVIS_BRANCH}" - echo "${TRAVIS_BRANCH}"
@ -68,7 +75,7 @@ after_success:
- | - |
if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ] && [ -n "$DEPLOY_MAT" ] if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ] && [ -n "$DEPLOY_MAT" ]
then then
echo "Updating docs" && cd $TRAVIS_BUILD_DIR && .ci/build_docs.sh echo "Updating docs" && cd $TRAVIS_BUILD_DIR && .ci/build_docs.sh
fi fi
deploy: deploy:
provider: releases provider: releases

View File

@ -1,12 +1,8 @@
#include <CLI/CLI.hpp> #include <CLI/CLI.hpp>
enum Level : std::int32_t { enum Level : std::int32_t { High, Medium, Low };
High,
Medium,
Low
};
int main(int argc, char** argv) { int main(int argc, char **argv) {
CLI::App app; CLI::App app;
Level level; Level level;
@ -15,9 +11,8 @@ int main(int argc, char** argv) {
try { try {
app.parse(argc, argv); app.parse(argc, argv);
} catch (CLI::Error const& e) { } catch(CLI::Error const &e) {
app.exit(e); app.exit(e);
} }
return 0; return 0;
} }

View File

@ -6,8 +6,7 @@ int main(int argc, char **argv) {
app.prefix_command(); app.prefix_command();
std::vector<int> vals; std::vector<int> vals;
app.add_option("--vals,-v", vals) app.add_option("--vals,-v", vals)->expected(1);
->expected(1);
std::vector<std::string> more_comms; std::vector<std::string> more_comms;
try { try {
@ -19,7 +18,7 @@ int main(int argc, char **argv) {
std::cout << "Prefix:"; std::cout << "Prefix:";
for(int v : vals) for(int v : vals)
std::cout << v << ":"; std::cout << v << ":";
std::cout << std::endl << "Remaining commands: "; std::cout << std::endl << "Remaining commands: ";
// Perfer to loop over from beginning, not "pop" order // Perfer to loop over from beginning, not "pop" order

View File

@ -59,7 +59,7 @@ class App {
/// If true, return immediatly on an unrecognised option (implies allow_extras) /// If true, return immediatly on an unrecognised option (implies allow_extras)
bool prefix_command_{false}; bool prefix_command_{false};
/// This is a function that runs when complete. Great for subcommands. Can throw. /// This is a function that runs when complete. Great for subcommands. Can throw.
std::function<void()> callback_; std::function<void()> callback_;
@ -160,7 +160,7 @@ class App {
prefix_command_ = allow; prefix_command_ = allow;
return this; return this;
} }
/// Ignore case. Subcommand inherit value. /// Ignore case. Subcommand inherit value.
App *ignore_case(bool value = true) { App *ignore_case(bool value = true) {
ignore_case_ = value; ignore_case_ = value;
@ -225,8 +225,6 @@ class App {
} else } else
throw OptionAlreadyAdded(myopt.get_name()); throw OptionAlreadyAdded(myopt.get_name());
} }
/// Add option for non-vectors (duplicate copy needed without defaulted to avoid `iostream << value`) /// Add option for non-vectors (duplicate copy needed without defaulted to avoid `iostream << value`)
template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy> template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
@ -251,13 +249,13 @@ class App {
T &variable, ///< The variable to set T &variable, ///< The variable to set
std::string description, std::string description,
bool defaulted) { bool defaulted) {
CLI::callback_t fun = [&variable](CLI::results_t res) { CLI::callback_t fun = [&variable](CLI::results_t res) {
if(res.size() != 1) if(res.size() != 1)
return false; return false;
return detail::lexical_cast(res[0], variable); return detail::lexical_cast(res[0], variable);
}; };
Option *opt = add_option(name, fun, description, defaulted); Option *opt = add_option(name, fun, description, defaulted);
opt->set_custom_option(detail::type_name<T>()); opt->set_custom_option(detail::type_name<T>());
if(defaulted) { if(defaulted) {
@ -267,13 +265,13 @@ class App {
} }
return opt; return opt;
} }
/// Add option for vectors (no default) /// Add option for vectors (no default)
template <typename T> template <typename T>
Option *add_option(std::string name, Option *add_option(std::string name,
std::vector<T> &variable, ///< The variable vector to set std::vector<T> &variable, ///< The variable vector to set
std::string description = "") { std::string description = "") {
CLI::callback_t fun = [&variable](CLI::results_t res) { CLI::callback_t fun = [&variable](CLI::results_t res) {
bool retval = true; bool retval = true;
variable.clear(); variable.clear();
@ -283,12 +281,12 @@ class App {
} }
return (!variable.empty()) && retval; return (!variable.empty()) && retval;
}; };
Option *opt = add_option(name, fun, description, false); Option *opt = add_option(name, fun, description, false);
opt->set_custom_option(detail::type_name<T>(), -1, true); opt->set_custom_option(detail::type_name<T>(), -1, true);
return opt; return opt;
} }
/// Add option for vectors /// Add option for vectors
template <typename T> template <typename T>
Option *add_option(std::string name, Option *add_option(std::string name,
@ -386,7 +384,7 @@ class App {
opt->set_custom_option(typeval); opt->set_custom_option(typeval);
return opt; return opt;
} }
/// Add set of options /// Add set of options
template <typename T> template <typename T>
Option *add_set(std::string name, Option *add_set(std::string name,
@ -394,7 +392,7 @@ class App {
std::set<T> options, ///< The set of posibilities std::set<T> options, ///< The set of posibilities
std::string description, std::string description,
bool defaulted) { bool defaulted) {
CLI::callback_t fun = [&member, options](CLI::results_t res) { CLI::callback_t fun = [&member, options](CLI::results_t res) {
if(res.size() != 1) { if(res.size() != 1) {
return false; return false;
@ -404,7 +402,7 @@ class App {
return false; return false;
return std::find(std::begin(options), std::end(options), member) != std::end(options); return std::find(std::begin(options), std::end(options), member) != std::end(options);
}; };
Option *opt = add_option(name, fun, description, defaulted); Option *opt = add_option(name, fun, description, defaulted);
std::string typeval = detail::type_name<T>(); std::string typeval = detail::type_name<T>();
typeval += " in {" + detail::join(options) + "}"; typeval += " in {" + detail::join(options) + "}";
@ -443,17 +441,17 @@ class App {
std::string typeval = detail::type_name<std::string>(); std::string typeval = detail::type_name<std::string>();
typeval += " in {" + detail::join(options) + "}"; typeval += " in {" + detail::join(options) + "}";
opt->set_custom_option(typeval); opt->set_custom_option(typeval);
return opt; return opt;
} }
/// Add set of options, string only, ignore case /// Add set of options, string only, ignore case
Option *add_set_ignore_case(std::string name, Option *add_set_ignore_case(std::string name,
std::string &member, ///< The selected member of the set std::string &member, ///< The selected member of the set
std::set<std::string> options, ///< The set of posibilities std::set<std::string> options, ///< The set of posibilities
std::string description, std::string description,
bool defaulted) { bool defaulted) {
CLI::callback_t fun = [&member, options](CLI::results_t res) { CLI::callback_t fun = [&member, options](CLI::results_t res) {
if(res.size() != 1) { if(res.size() != 1) {
return false; return false;
@ -469,7 +467,7 @@ class App {
return true; return true;
} }
}; };
Option *opt = add_option(name, fun, description, defaulted); Option *opt = add_option(name, fun, description, defaulted);
std::string typeval = detail::type_name<std::string>(); std::string typeval = detail::type_name<std::string>();
typeval += " in {" + detail::join(options) + "}"; typeval += " in {" + detail::join(options) + "}";
@ -912,19 +910,19 @@ class App {
char *buffer = nullptr; char *buffer = nullptr;
std::string ename_string; std::string ename_string;
#ifdef _MSC_VER #ifdef _MSC_VER
// Windows version // Windows version
size_t sz = 0; size_t sz = 0;
if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) { if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
ename_string = std::string(buffer); ename_string = std::string(buffer);
free(buffer); free(buffer);
} }
#else #else
// This also works on Windows, but gives a warning // This also works on Windows, but gives a warning
buffer = std::getenv(opt->envname_.c_str()); buffer = std::getenv(opt->envname_.c_str());
if(buffer != nullptr) if(buffer != nullptr)
ename_string = std::string(buffer); ename_string = std::string(buffer);
#endif #endif
if(!ename_string.empty()) { if(!ename_string.empty()) {
opt->add_result(ename_string); opt->add_result(ename_string);
@ -1068,10 +1066,8 @@ class App {
size_t _count_remaining_required_positionals() const { size_t _count_remaining_required_positionals() const {
size_t retval = 0; size_t retval = 0;
for(const Option_p &opt : options_) for(const Option_p &opt : options_)
if(opt->get_positional() if(opt->get_positional() && opt->get_required() && opt->get_expected() > 0 &&
&& opt->get_required() static_cast<int>(opt->count()) < opt->get_expected())
&& opt->get_expected() > 0
&& static_cast<int>(opt->count()) < opt->get_expected())
retval = static_cast<size_t>(opt->get_expected()) - opt->count(); retval = static_cast<size_t>(opt->get_expected()) - opt->count();
return retval; return retval;
@ -1098,7 +1094,7 @@ class App {
else { else {
args.pop_back(); args.pop_back();
missing()->emplace_back(detail::Classifer::NONE, positional); missing()->emplace_back(detail::Classifer::NONE, positional);
if(prefix_command_) { if(prefix_command_) {
while(!args.empty()) { while(!args.empty()) {
missing()->emplace_back(detail::Classifer::NONE, args.back()); missing()->emplace_back(detail::Classifer::NONE, args.back());
@ -1106,7 +1102,6 @@ class App {
} }
} }
} }
} }
/// Parse a subcommand, modify args and continue /// Parse a subcommand, modify args and continue

View File

@ -433,9 +433,8 @@ class Option {
/// Set the default value string representation /// Set the default value string representation
void set_default_val(std::string val) { defaultval_ = val; } void set_default_val(std::string val) { defaultval_ = val; }
/// Set the type name displayed on this option /// Set the type name displayed on this option
void set_type_name(std::string val) {typeval_ = val;} void set_type_name(std::string val) { typeval_ = val; }
///@} ///@}

View File

@ -75,9 +75,8 @@ constexpr const char *type_name() {
// Lexical cast // Lexical cast
/// Integers / enums /// Integers / enums
template <typename T, enable_if_t<std::is_integral<T>::value template <typename T,
|| std::is_enum<T>::value enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value, detail::enabler> = detail::dummy>
, detail::enabler> = detail::dummy>
bool lexical_cast(std::string input, T &output) { bool lexical_cast(std::string input, T &output) {
try { try {
output = static_cast<T>(std::stoll(input)); output = static_cast<T>(std::stoll(input));
@ -103,11 +102,9 @@ bool lexical_cast(std::string input, T &output) {
} }
/// String and similar /// String and similar
template < template <typename T,
typename T, enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value,
enable_if_t<!std::is_floating_point<T>::value detail::enabler> = detail::dummy>
&& !std::is_integral<T>::value
&& !std::is_enum<T>::value, detail::enabler> = detail::dummy>
bool lexical_cast(std::string input, T &output) { bool lexical_cast(std::string input, T &output) {
output = input; output = input;
return true; return true;

View File

@ -204,34 +204,25 @@ TEST_F(TApp, DefaultOpts) {
} }
TEST_F(TApp, EnumTest) { TEST_F(TApp, EnumTest) {
enum Level : std::int32_t { enum Level : std::int32_t { High, Medium, Low };
High,
Medium,
Low
};
Level level = Level::Low; Level level = Level::Low;
app.add_option("--level", level); app.add_option("--level", level);
args = {"--level", "1"}; args = {"--level", "1"};
run(); run();
EXPECT_EQ(level, Level::Medium); EXPECT_EQ(level, Level::Medium);
} }
TEST_F(TApp, NewEnumTest) { TEST_F(TApp, NewEnumTest) {
enum class Level2 : std::int32_t { enum class Level2 : std::int32_t { High, Medium, Low };
High,
Medium,
Low
};
Level2 level = Level2::Low; Level2 level = Level2::Low;
app.add_option("--level", level); app.add_option("--level", level);
args = {"--level", "1"}; args = {"--level", "1"};
run(); run();
EXPECT_EQ(level, Level2::Medium); EXPECT_EQ(level, Level2::Medium);
} }
TEST_F(TApp, RequiredFlags) { TEST_F(TApp, RequiredFlags) {
app.add_flag("-a")->required(); app.add_flag("-a")->required();
app.add_flag("-b")->mandatory(); // Alternate term app.add_flag("-b")->mandatory(); // Alternate term
@ -440,7 +431,6 @@ TEST_F(TApp, InSetWithDefault) {
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
TEST_F(TApp, InCaselessSetWithDefault) { TEST_F(TApp, InCaselessSetWithDefault) {
std::string choice = "one"; std::string choice = "one";
@ -532,7 +522,6 @@ TEST_F(TApp, VectorFixedString) {
EXPECT_EQ(answer, strvec); EXPECT_EQ(answer, strvec);
} }
TEST_F(TApp, VectorDefaultedFixedString) { TEST_F(TApp, VectorDefaultedFixedString) {
std::vector<std::string> strvec{"one"}; std::vector<std::string> strvec{"one"};
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"}; std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
@ -895,40 +884,40 @@ TEST_F(TApp, CheckSubcomFail) {
// Added to test defaults on dual method // Added to test defaults on dual method
TEST_F(TApp, OptionWithDefaults) { TEST_F(TApp, OptionWithDefaults) {
int someint=2; int someint = 2;
app.add_option("-a", someint, "", true); app.add_option("-a", someint, "", true);
args = {"-a1", "-a2"}; args = {"-a1", "-a2"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
// Added to test defaults on dual method // Added to test defaults on dual method
TEST_F(TApp, SetWithDefaults) { TEST_F(TApp, SetWithDefaults) {
int someint=2; int someint = 2;
app.add_set("-a", someint, {1,2,3,4}, "", true); app.add_set("-a", someint, {1, 2, 3, 4}, "", true);
args = {"-a1", "-a2"}; args = {"-a1", "-a2"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
// Added to test defaults on dual method // Added to test defaults on dual method
TEST_F(TApp, SetWithDefaultsConversion) { TEST_F(TApp, SetWithDefaultsConversion) {
int someint=2; int someint = 2;
app.add_set("-a", someint, {1,2,3,4}, "", true); app.add_set("-a", someint, {1, 2, 3, 4}, "", true);
args = {"-a", "hi"}; args = {"-a", "hi"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
// Added to test defaults on dual method // Added to test defaults on dual method
TEST_F(TApp, SetWithDefaultsIC) { TEST_F(TApp, SetWithDefaultsIC) {
std::string someint="ho"; std::string someint = "ho";
app.add_set_ignore_case("-a", someint, {"Hi", "Ho"}, "", true); app.add_set_ignore_case("-a", someint, {"Hi", "Ho"}, "", true);
args = {"-aHi", "-aHo"}; args = {"-aHi", "-aHo"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }

View File

@ -307,16 +307,15 @@ TEST_F(TApp, BadSubcomSearch) {
} }
TEST_F(TApp, PrefixProgram) { TEST_F(TApp, PrefixProgram) {
app.prefix_command(); app.prefix_command();
app.add_flag("--simple"); app.add_flag("--simple");
args = {"--simple", "other", "--simple", "--mine"}; args = {"--simple", "other", "--simple", "--mine"};
auto ret_args = run(); auto ret_args = run();
EXPECT_EQ(ret_args, std::vector<std::string>({"--mine", "--simple", "other"})); EXPECT_EQ(ret_args, std::vector<std::string>({"--mine", "--simple", "other"}));
} }
struct SubcommandProgram : public TApp { struct SubcommandProgram : public TApp {