Skip to content

Commit 6d22f0a

Browse files
committed
CPP-AP: version 1.2
- Added the `demo` workflow - Cleanup of the scripts, CMake and workflow files - Improved error logic for argument value getting
1 parent b9fdeaa commit 6d22f0a

File tree

9 files changed

+134
-85
lines changed

9 files changed

+134
-85
lines changed

.github/workflows/licence.yaml renamed to .github/workflows/license.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
name: licence
1+
name: license
22
on:
33
push:
44
branches:
55
- '*'
66
paths:
7-
- .github/workflows/licence.yaml
7+
- .github/workflows/license.yaml
88
- scripts/check_licence.py
99
- include/**
1010

@@ -25,4 +25,4 @@ jobs:
2525
- name: Test licence
2626
shell: bash
2727
run: |
28-
python3 scripts/check_licence.py
28+
python3 scripts/check_license.py

Doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ PROJECT_NAME = "CPP-AP"
4848
# could be handy for archiving the generated documentation or if some version
4949
# control system is used.
5050

51-
PROJECT_NUMBER = 1.1.1
51+
PROJECT_NUMBER = 1.2
5252

5353
# Using the PROJECT_BRIEF tag one can provide an optional one line description
5454
# for a project that appears at the top of each page and should give viewer a

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The `CPP-AP` library does not require installing any additional tools or heavy l
4545
- [Formatting](#formatting)
4646
- [Documentation](#documentation)
4747
- [Compiler support](#compiler-support)
48-
- [Licence](#licence)
48+
- [License](#license)
4949

5050
<br />
5151
<br />
@@ -587,6 +587,6 @@ The documentation for this project can be generated using Doxygen:
587587
<br />
588588
<br />
589589
590-
## Licence
590+
## License
591591
592-
The `CPP-AP` project uses the [MIT Licence](https://mit-license.org/) which can be found in the [LICENCE](/LICENSE) file
592+
The `CPP-AP` project uses the [MIT License](https://mit-license.org/) which can be found in the [LICENSE](/LICENSE) file

include/ap/argument_parser.hpp

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
1-
// Copyright (c) 2023-2024 Jakub Musiał
2-
// This file is part of the CPP-AP project (https://github.com/SpectraL519/cpp-ap).
3-
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
1+
/*
2+
CPP-AP: Command-line argument parser for C++20
3+
4+
MIT License
5+
6+
Copyright (c) 2023-2024 Jakub Musiał and other contributors
7+
https://github.com/SpectraL519/cpp-ap
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in all
17+
copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
SOFTWARE.
26+
*/
427

528
/*!
629
* @file argument_parser.hpp
7-
* @brief CPP-AP library header file.
30+
* @brief CPP-AP library source file.
831
*
932
* This header file contians the entire CPP-AP library implementation.
1033
*
11-
* @version 1.1
34+
* @version 1.2
1235
*/
1336

1437
#pragma once
@@ -55,22 +78,22 @@ namespace utility {
5578
* @tparam T Type to check.
5679
*/
5780
template <typename T>
58-
concept readable = requires(T value, std::istream& input_stream) { input_stream >> value; };
81+
concept c_readable = requires(T value, std::istream& input_stream) { input_stream >> value; };
5982

6083
/**
61-
* @brief The concept is satisfied when `T` is readable, copy constructible and assignable.
84+
* @brief The concept is satisfied when `T` is c_readable, copy constructible and assignable.
6285
* @tparam T Type to check.
6386
*/
6487
template <typename T>
65-
concept valid_argument_value_type =
66-
readable<T> and std::copy_constructible<T> and std::assignable_from<T&, const T&>;
88+
concept c_argument_value_type =
89+
c_readable<T> and std::copy_constructible<T> and std::assignable_from<T&, const T&>;
6790

6891
/**
6992
* @brief The concept is satisfied when `T` is comparable using the equality operator `==`.
7093
* @tparam T Type to check.
7194
*/
7295
template <typename T>
73-
concept equality_comparable = requires(T lhs, T rhs) {
96+
concept c_equality_comparable = requires(T lhs, T rhs) {
7497
{ lhs == rhs } -> std::convertible_to<bool>;
7598
};
7699

@@ -556,13 +579,13 @@ class range {
556579

557580
/// @brief Defines valued argument action traits.
558581
struct valued_action {
559-
template <ap::utility::valid_argument_value_type T>
582+
template <ap::utility::c_argument_value_type T>
560583
using type = std::function<T(const T&)>;
561584
};
562585

563586
/// @brief Defines void argument action traits.
564587
struct void_action {
565-
template <ap::utility::valid_argument_value_type T>
588+
template <ap::utility::c_argument_value_type T>
566589
using type = std::function<void(T&)>;
567590
};
568591

@@ -581,15 +604,14 @@ namespace detail {
581604
* @tparam AS The action specifier type.
582605
*/
583606
template <typename AS>
584-
concept valid_action_specifier =
585-
ap::utility::is_valid_type_v<AS, ap::valued_action, ap::void_action>;
607+
concept c_action_specifier = ap::utility::is_valid_type_v<AS, ap::valued_action, ap::void_action>;
586608

587609
/// @brief Template argument action callable type alias.
588-
template <valid_action_specifier AS, ap::utility::valid_argument_value_type T>
610+
template <c_action_specifier AS, ap::utility::c_argument_value_type T>
589611
using callable_type = typename AS::template type<T>;
590612

591613
/// @brief Template argument action callabla variant type alias.
592-
template <ap::utility::valid_argument_value_type T>
614+
template <ap::utility::c_argument_value_type T>
593615
using action_variant_type =
594616
std::variant<callable_type<ap::valued_action, T>, callable_type<ap::void_action, T>>;
595617

@@ -599,15 +621,15 @@ using action_variant_type =
599621
* @param action The action variant.
600622
* @return True if the held action is a void action.
601623
*/
602-
template <ap::utility::valid_argument_value_type T>
624+
template <ap::utility::c_argument_value_type T>
603625
[[nodiscard]] inline bool is_void_action(const action_variant_type<T>& action) noexcept {
604626
return std::holds_alternative<callable_type<ap::void_action, T>>(action);
605627
}
606628

607629
} // namespace detail
608630

609631
/// @brief Returns a default argument action.
610-
template <ap::utility::valid_argument_value_type T>
632+
template <ap::utility::c_argument_value_type T>
611633
detail::callable_type<ap::void_action, T> default_action() noexcept {
612634
return [](T&) {};
613635
}
@@ -629,7 +651,7 @@ namespace argument {
629651
* @brief "Positional argument class of type T.
630652
* @tparam T The type of the argument value.
631653
*/
632-
template <utility::valid_argument_value_type T = std::string>
654+
template <utility::c_argument_value_type T = std::string>
633655
class positional_argument : public detail::argument_interface {
634656
public:
635657
using value_type = T; ///< Type of the argument value.
@@ -672,7 +694,7 @@ class positional_argument : public detail::argument_interface {
672694
* @note Requires T to be equality comparable.
673695
*/
674696
positional_argument& choices(const std::vector<value_type>& choices) noexcept
675-
requires(utility::equality_comparable<value_type>)
697+
requires(utility::c_equality_comparable<value_type>)
676698
{
677699
this->_choices = choices;
678700
return *this;
@@ -685,7 +707,7 @@ class positional_argument : public detail::argument_interface {
685707
* @param action The action function to set.
686708
* @return Reference to the positional_argument.
687709
*/
688-
template <ap::action::detail::valid_action_specifier AS, std::invocable<value_type&> F>
710+
template <ap::action::detail::c_action_specifier AS, std::invocable<value_type&> F>
689711
positional_argument& action(F&& action) noexcept {
690712
using callable_type = ap::action::detail::callable_type<AS, value_type>;
691713
this->_action = std::forward<callable_type>(action);
@@ -847,7 +869,7 @@ class positional_argument : public detail::argument_interface {
847869
* @brief Optional argument class of type T.
848870
* @tparam T The type of the argument value.
849871
*/
850-
template <utility::valid_argument_value_type T = std::string>
872+
template <utility::c_argument_value_type T = std::string>
851873
class optional_argument : public detail::argument_interface {
852874
public:
853875
using value_type = T;
@@ -940,7 +962,7 @@ class optional_argument : public detail::argument_interface {
940962
* @param action The action function to set.
941963
* @return Reference to the optional_argument.
942964
*/
943-
template <ap::action::detail::valid_action_specifier AS, std::invocable<value_type&> F>
965+
template <ap::action::detail::c_action_specifier AS, std::invocable<value_type&> F>
944966
optional_argument& action(F&& action) noexcept {
945967
using callable_type = ap::action::detail::callable_type<AS, value_type>;
946968
this->_action = std::forward<callable_type>(action);
@@ -954,7 +976,7 @@ class optional_argument : public detail::argument_interface {
954976
* @note Requires T to be equality comparable.
955977
*/
956978
optional_argument& choices(const std::vector<value_type>& choices) noexcept
957-
requires(utility::equality_comparable<value_type>)
979+
requires(utility::c_equality_comparable<value_type>)
958980
{
959981
this->_choices = choices;
960982
return *this;
@@ -1239,7 +1261,7 @@ class argument_parser {
12391261
* @param primary_name The primary name of the argument.
12401262
* @return Reference to the added positional argument.
12411263
*/
1242-
template <utility::valid_argument_value_type T = std::string>
1264+
template <utility::c_argument_value_type T = std::string>
12431265
argument::positional_argument<T>& add_positional_argument(std::string_view primary_name) {
12441266
// TODO: check forbidden characters
12451267

@@ -1259,7 +1281,7 @@ class argument_parser {
12591281
* @param secondary_name The secondary name of the argument.
12601282
* @return Reference to the added positional argument.
12611283
*/
1262-
template <utility::valid_argument_value_type T = std::string>
1284+
template <utility::c_argument_value_type T = std::string>
12631285
argument::positional_argument<T>& add_positional_argument(
12641286
std::string_view primary_name, std::string_view secondary_name
12651287
) {
@@ -1280,7 +1302,7 @@ class argument_parser {
12801302
* @param primary_name The primary name of the argument.
12811303
* @return Reference to the added optional argument.
12821304
*/
1283-
template <utility::valid_argument_value_type T = std::string>
1305+
template <utility::c_argument_value_type T = std::string>
12841306
argument::optional_argument<T>& add_optional_argument(std::string_view primary_name) {
12851307
// TODO: check forbidden characters
12861308

@@ -1299,7 +1321,7 @@ class argument_parser {
12991321
* @param secondary_name The secondary name of the argument.
13001322
* @return Reference to the added optional argument.
13011323
*/
1302-
template <utility::valid_argument_value_type T = std::string>
1324+
template <utility::c_argument_value_type T = std::string>
13031325
argument::optional_argument<T>& add_optional_argument(
13041326
std::string_view primary_name, std::string_view secondary_name
13051327
) {

scripts/check_licence.py renamed to scripts/check_license.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
import argparse
22
import sys
3+
from collections.abc import Iterable
34
from enum import IntEnum
45
from pathlib import Path
56

67
from common import find_files
78

89

9-
LICENCE_INFO = [
10-
"// Copyright (c) 2023-2024 Jakub Musiał",
11-
"// This file is part of the CPP-AP project (https://github.com/SpectraL519/cpp-ap).",
12-
"// Licensed under the MIT License. See the LICENSE file in the project root for full license information.",
13-
]
10+
ADDITIONAL_LICENCE_INFO = ["CPP-AP: Command-line argument parser for C++20"]
1411

1512

1613
class DefaultParameters:
14+
licence_file: Path = Path("LICENSE")
1715
search_paths: list[str] = ["include"]
1816
file_patterns: list[str] = ["*.cpp", "*.hpp", "*.c", "*.h"]
1917
exclude_paths: list[str] = []
@@ -22,6 +20,13 @@ class DefaultParameters:
2220

2321
def parse_args():
2422
parser = argparse.ArgumentParser()
23+
parser.add_argument(
24+
"-l", "--licence-file",
25+
type=Path,
26+
default=DefaultParameters.licence_file,
27+
nargs="?",
28+
help="path to the licence file"
29+
)
2530
parser.add_argument(
2631
"-p", "--search-paths",
2732
type=str,
@@ -50,14 +55,28 @@ def parse_args():
5055
return vars(parser.parse_args())
5156

5257

58+
def expected_licence(licence_file: Path, pre: Iterable[str] = None, post: Iterable[str] = None) -> list[str]:
59+
with licence_file.open("r", encoding="utf-8") as f:
60+
licence_content = f.read().splitlines()
61+
62+
content = []
63+
if pre:
64+
content.extend([*pre, ""])
65+
content.extend(licence_content)
66+
if post:
67+
content.extend(["", *post])
68+
69+
return ["/*", *content, "*/"]
70+
71+
5372
class ReturnCode(IntEnum):
5473
ok = 0
5574
file_to_short = -1
5675
missing_licence = -2
5776
invalid_licence = -3
5877

5978

60-
def check_licence(files: set[Path]) -> int:
79+
def check_licence(expected_licence: Iterable[str], files: set[Path]) -> int:
6180
n_files = len(files)
6281
print(f"Files to check: {n_files}")
6382

@@ -66,7 +85,7 @@ def _set_return_code(c: ReturnCode):
6685
nonlocal return_code
6786
return_code = c if not return_code else return_code
6887

69-
n_licence_lines = len(LICENCE_INFO)
88+
n_licence_lines = len(expected_licence)
7089

7190
def _check_file(file: Path):
7291
with open(file, "r", encoding="utf-8") as f:
@@ -78,7 +97,7 @@ def _check_file(file: Path):
7897
print(f"[Licence error] File `{file}` to short")
7998
return
8099

81-
matching_lines = [lines[i] == LICENCE_INFO[i] for i in range(n_licence_lines)]
100+
matching_lines = [lines[i] == expected_licence[i] for i in range(n_licence_lines)]
82101
correct_licence = all(matching_lines)
83102
if not correct_licence:
84103
missing_info = any(matching_lines)
@@ -94,16 +113,22 @@ def _check_file(file: Path):
94113
print(f"[{i + 1}/{n_files}] {file}")
95114
_check_file(file)
96115

116+
print("Done!")
117+
97118
return return_code
98119

99120

100121
def main(
101-
search_paths: list[str],
102-
file_patterns: list[str],
103-
exclude_paths: list[str]
122+
licence_file: Path,
123+
search_paths: Iterable[str],
124+
file_patterns: Iterable[str],
125+
exclude_paths: Iterable[str]
104126
):
105127
files_to_check = find_files(search_paths, file_patterns, exclude_paths)
106-
sys.exit(check_licence(files_to_check))
128+
sys.exit(check_licence(
129+
expected_licence(licence_file, pre=ADDITIONAL_LICENCE_INFO),
130+
files_to_check
131+
))
107132

108133

109134
if __name__ == "__main__":

scripts/common.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
from collections.abc import Iterable
12
from pathlib import Path
23

34

45
def find_files(
5-
search_paths: list[str],
6-
file_patterns: list[str],
7-
exclude_paths: list[str]
6+
search_paths: Iterable[str],
7+
file_patterns: Iterable[str],
8+
exclude_paths: Iterable[str]
89
) -> set[Path]:
910
matching_files = []
1011
for search_path in search_paths:

0 commit comments

Comments
 (0)