diff --git a/.ci/check_style.sh b/.ci/check_style.sh new file mode 100755 index 00000000..ed6fa4f4 --- /dev/null +++ b/.ci/check_style.sh @@ -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 diff --git a/.ci/prepare_altern.sh b/.ci/prepare_altern.sh index 24f63777..e384b003 100644 --- a/.ci/prepare_altern.sh +++ b/.ci/prepare_altern.sh @@ -9,6 +9,8 @@ if [ "$CXX" = "g++" ] ; then else 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 export PATH="${DEPS_DIR}/extrabin":$PATH diff --git a/.ci/travis.sh b/.ci/travis.sh index 66f6192f..c2108d3d 100755 --- a/.ci/travis.sh +++ b/.ci/travis.sh @@ -6,3 +6,5 @@ cd build cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug cmake --build . -- -j2 ctest --output-on-failure + +set +evx diff --git a/.travis.yml b/.travis.yml index 4bc76b85..e95a33be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,16 @@ matrix: - compiler: clang addons: apt: - sources: - - llvm-toolchain-precise-3.5 - - ubuntu-toolchain-r-test + packages: + - clang-3.9 + - clang-format-3.9 + - clang-tidy-3.9 + env: + - COMPILER=3.9 + - CHECK_STYLE=yes + - compiler: clang + addons: + apt: packages: - clang-3.5 env: @@ -37,8 +44,6 @@ matrix: - compiler: gcc addons: apt: - sources: - - ubuntu-toolchain-r-test packages: - g++-4.7 env: @@ -48,19 +53,21 @@ matrix: install: - python -c 'import sys; print(sys.version_info[:])' - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" -- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd $TRAVIS_BUILD_DIR && . .ci/prepare_altern.sh - ; 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_doxygen.sh - ; fi +- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd $TRAVIS_BUILD_DIR && . .ci/prepare_altern.sh ; 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_doxygen.sh ; fi - if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_lcov.sh ; fi - cd "${DEPS_DIR}" -- if [ "$(python -c 'import sys; print(sys.version_info[0])')" = "2" ] ; then pip - install --user pathlib; fi +- if [ "$(python -c 'import sys; print(sys.version_info[0])')" = "2" ] ; then pip install --user pathlib ; fi script: - cd "${TRAVIS_BUILD_DIR}" -- .ci/travis.sh +- | + if [ -n "$CHECK_STYLE" ] + then + .ci/check_style.sh + else + .ci/travis.sh + fi after_success: - if [ -n "$COVERALLS" ] ; then cd $TRAVIS_BUILD_DIR && .ci/run_codecov.sh ; fi - echo "${TRAVIS_BRANCH}" @@ -68,7 +75,7 @@ after_success: - | if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ] && [ -n "$DEPLOY_MAT" ] then - echo "Updating docs" && cd $TRAVIS_BUILD_DIR && .ci/build_docs.sh + echo "Updating docs" && cd $TRAVIS_BUILD_DIR && .ci/build_docs.sh fi deploy: provider: releases diff --git a/examples/enum.cpp b/examples/enum.cpp index ce97db39..c03799cf 100644 --- a/examples/enum.cpp +++ b/examples/enum.cpp @@ -1,12 +1,8 @@ #include -enum Level : std::int32_t { - High, - Medium, - Low -}; +enum Level : std::int32_t { High, Medium, Low }; -int main(int argc, char** argv) { +int main(int argc, char **argv) { CLI::App app; Level level; @@ -15,9 +11,8 @@ int main(int argc, char** argv) { try { app.parse(argc, argv); - } catch (CLI::Error const& e) { + } catch(CLI::Error const &e) { app.exit(e); } return 0; } - diff --git a/examples/prefix_command.cpp b/examples/prefix_command.cpp index 103ee833..dcf4f7ff 100644 --- a/examples/prefix_command.cpp +++ b/examples/prefix_command.cpp @@ -6,8 +6,7 @@ int main(int argc, char **argv) { app.prefix_command(); std::vector vals; - app.add_option("--vals,-v", vals) - ->expected(1); + app.add_option("--vals,-v", vals)->expected(1); std::vector more_comms; try { @@ -19,7 +18,7 @@ int main(int argc, char **argv) { std::cout << "Prefix:"; for(int v : vals) std::cout << v << ":"; - + std::cout << std::endl << "Remaining commands: "; // Perfer to loop over from beginning, not "pop" order diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 9ab4cd6a..cedef560 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -59,7 +59,7 @@ class App { /// If true, return immediatly on an unrecognised option (implies allow_extras) bool prefix_command_{false}; - + /// This is a function that runs when complete. Great for subcommands. Can throw. std::function callback_; @@ -160,7 +160,7 @@ class App { prefix_command_ = allow; return this; } - + /// Ignore case. Subcommand inherit value. App *ignore_case(bool value = true) { ignore_case_ = value; @@ -225,8 +225,6 @@ class App { } else throw OptionAlreadyAdded(myopt.get_name()); } - - /// Add option for non-vectors (duplicate copy needed without defaulted to avoid `iostream << value`) template ::value, detail::enabler> = detail::dummy> @@ -251,13 +249,13 @@ class App { T &variable, ///< The variable to set std::string description, bool defaulted) { - + CLI::callback_t fun = [&variable](CLI::results_t res) { if(res.size() != 1) return false; return detail::lexical_cast(res[0], variable); }; - + Option *opt = add_option(name, fun, description, defaulted); opt->set_custom_option(detail::type_name()); if(defaulted) { @@ -267,13 +265,13 @@ class App { } return opt; } - + /// Add option for vectors (no default) template Option *add_option(std::string name, std::vector &variable, ///< The variable vector to set std::string description = "") { - + CLI::callback_t fun = [&variable](CLI::results_t res) { bool retval = true; variable.clear(); @@ -283,12 +281,12 @@ class App { } return (!variable.empty()) && retval; }; - + Option *opt = add_option(name, fun, description, false); opt->set_custom_option(detail::type_name(), -1, true); return opt; } - + /// Add option for vectors template Option *add_option(std::string name, @@ -386,7 +384,7 @@ class App { opt->set_custom_option(typeval); return opt; } - + /// Add set of options template Option *add_set(std::string name, @@ -394,7 +392,7 @@ class App { std::set options, ///< The set of posibilities std::string description, bool defaulted) { - + CLI::callback_t fun = [&member, options](CLI::results_t res) { if(res.size() != 1) { return false; @@ -404,7 +402,7 @@ class App { return false; return std::find(std::begin(options), std::end(options), member) != std::end(options); }; - + Option *opt = add_option(name, fun, description, defaulted); std::string typeval = detail::type_name(); typeval += " in {" + detail::join(options) + "}"; @@ -443,17 +441,17 @@ class App { std::string typeval = detail::type_name(); typeval += " in {" + detail::join(options) + "}"; opt->set_custom_option(typeval); - + return opt; } - + /// Add set of options, string only, ignore case Option *add_set_ignore_case(std::string name, std::string &member, ///< The selected member of the set std::set options, ///< The set of posibilities std::string description, bool defaulted) { - + CLI::callback_t fun = [&member, options](CLI::results_t res) { if(res.size() != 1) { return false; @@ -469,7 +467,7 @@ class App { return true; } }; - + Option *opt = add_option(name, fun, description, defaulted); std::string typeval = detail::type_name(); typeval += " in {" + detail::join(options) + "}"; @@ -912,19 +910,19 @@ class App { char *buffer = nullptr; std::string ename_string; - #ifdef _MSC_VER +#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 +#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 +#endif if(!ename_string.empty()) { opt->add_result(ename_string); @@ -1068,10 +1066,8 @@ class App { size_t _count_remaining_required_positionals() const { size_t retval = 0; for(const Option_p &opt : options_) - if(opt->get_positional() - && opt->get_required() - && opt->get_expected() > 0 - && static_cast(opt->count()) < opt->get_expected()) + if(opt->get_positional() && opt->get_required() && opt->get_expected() > 0 && + static_cast(opt->count()) < opt->get_expected()) retval = static_cast(opt->get_expected()) - opt->count(); return retval; @@ -1098,7 +1094,7 @@ class App { else { args.pop_back(); missing()->emplace_back(detail::Classifer::NONE, positional); - + if(prefix_command_) { while(!args.empty()) { missing()->emplace_back(detail::Classifer::NONE, args.back()); @@ -1106,7 +1102,6 @@ class App { } } } - } /// Parse a subcommand, modify args and continue diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index ee74929a..7dbe40d1 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -433,9 +433,8 @@ class Option { /// Set the default value string representation void set_default_val(std::string val) { defaultval_ = val; } - /// 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; } ///@} diff --git a/include/CLI/TypeTools.hpp b/include/CLI/TypeTools.hpp index e43d1e2c..42140924 100644 --- a/include/CLI/TypeTools.hpp +++ b/include/CLI/TypeTools.hpp @@ -75,9 +75,8 @@ constexpr const char *type_name() { // Lexical cast /// Integers / enums -template ::value - || std::is_enum::value - , detail::enabler> = detail::dummy> +template ::value || std::is_enum::value, detail::enabler> = detail::dummy> bool lexical_cast(std::string input, T &output) { try { output = static_cast(std::stoll(input)); @@ -103,11 +102,9 @@ bool lexical_cast(std::string input, T &output) { } /// String and similar -template < - typename T, - enable_if_t::value - && !std::is_integral::value - && !std::is_enum::value, detail::enabler> = detail::dummy> +template ::value && !std::is_integral::value && !std::is_enum::value, + detail::enabler> = detail::dummy> bool lexical_cast(std::string input, T &output) { output = input; return true; diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index dd9a3684..2ddb4be7 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -204,34 +204,25 @@ TEST_F(TApp, DefaultOpts) { } TEST_F(TApp, EnumTest) { - enum Level : std::int32_t { - High, - Medium, - Low - }; + enum Level : std::int32_t { High, Medium, Low }; Level level = Level::Low; app.add_option("--level", level); - + args = {"--level", "1"}; run(); EXPECT_EQ(level, Level::Medium); } TEST_F(TApp, NewEnumTest) { - enum class Level2 : std::int32_t { - High, - Medium, - Low - }; + enum class Level2 : std::int32_t { High, Medium, Low }; Level2 level = Level2::Low; app.add_option("--level", level); - + args = {"--level", "1"}; run(); EXPECT_EQ(level, Level2::Medium); } - TEST_F(TApp, RequiredFlags) { app.add_flag("-a")->required(); app.add_flag("-b")->mandatory(); // Alternate term @@ -440,7 +431,6 @@ TEST_F(TApp, InSetWithDefault) { EXPECT_THROW(run(), CLI::ConversionError); } - TEST_F(TApp, InCaselessSetWithDefault) { std::string choice = "one"; @@ -532,7 +522,6 @@ TEST_F(TApp, VectorFixedString) { EXPECT_EQ(answer, strvec); } - TEST_F(TApp, VectorDefaultedFixedString) { std::vector strvec{"one"}; std::vector answer{"mystring", "mystring2", "mystring3"}; @@ -895,40 +884,40 @@ TEST_F(TApp, CheckSubcomFail) { // Added to test defaults on dual method TEST_F(TApp, OptionWithDefaults) { - int someint=2; + int someint = 2; app.add_option("-a", someint, "", true); - + args = {"-a1", "-a2"}; - + EXPECT_THROW(run(), CLI::ConversionError); } // Added to test defaults on dual method TEST_F(TApp, SetWithDefaults) { - int someint=2; - app.add_set("-a", someint, {1,2,3,4}, "", true); - + int someint = 2; + app.add_set("-a", someint, {1, 2, 3, 4}, "", true); + args = {"-a1", "-a2"}; - + EXPECT_THROW(run(), CLI::ConversionError); } // Added to test defaults on dual method TEST_F(TApp, SetWithDefaultsConversion) { - int someint=2; - app.add_set("-a", someint, {1,2,3,4}, "", true); - + int someint = 2; + app.add_set("-a", someint, {1, 2, 3, 4}, "", true); + args = {"-a", "hi"}; - + EXPECT_THROW(run(), CLI::ConversionError); } // Added to test defaults on dual method TEST_F(TApp, SetWithDefaultsIC) { - std::string someint="ho"; + std::string someint = "ho"; app.add_set_ignore_case("-a", someint, {"Hi", "Ho"}, "", true); - + args = {"-aHi", "-aHo"}; - + EXPECT_THROW(run(), CLI::ConversionError); } diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index 21c26c28..6e2e7e05 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -307,16 +307,15 @@ TEST_F(TApp, BadSubcomSearch) { } TEST_F(TApp, PrefixProgram) { - + app.prefix_command(); - + app.add_flag("--simple"); - + args = {"--simple", "other", "--simple", "--mine"}; auto ret_args = run(); - + EXPECT_EQ(ret_args, std::vector({"--mine", "--simple", "other"})); - } struct SubcommandProgram : public TApp {