Skip to content

Commit f9c5c7b

Browse files
authored
Merge pull request #285 from eseiler/feature/copy_metadata_to_subparser
[FEATURE] Copy some metadata to subparsers
2 parents 4480a90 + a6f81c3 commit f9c5c7b

File tree

4 files changed

+112
-14
lines changed

4 files changed

+112
-14
lines changed

doc/howto/subcommand_parser/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ max$ ./mygit push -h
4848
then the sub-parser will be named `mygit-push` and will be instantiated with all arguments
4949
followed by the keyword `push` which in this case triggers printing the help page (`-h`).
5050

51+
Additionally, the following metadata will be copied from the top-level parser to the sub-parser:
52+
* sharg::parser::info::version
53+
* sharg::parser::info::author
54+
* sharg::parser::info::email
55+
* sharg::parser::info::date
56+
* sharg::parser::info::url
57+
* sharg::parser::info::short_copyright
58+
* sharg::parser::info::long_copyright
59+
* sharg::parser::info::citation
60+
5161
That's it. Here is a full example of a subcommand parser you can try and adjust to your needs:
5262

5363
\include doc/howto/subcommand_parser/subcommand_parse.cpp

include/sharg/auxiliary.hpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ class vector_of_string : public std::vector<std::string>
7777
* The meta information is assembled in a struct to provide a central access
7878
* point that can be easily extended.
7979
*
80+
* ### Subparser
81+
*
82+
* When \link subcommand_parse using a subparser \endlink, the subcommand will be appended to the
83+
* subparser's #app_name.
84+
* Additionally, the following metadata will be copied from the top-level parser to the sub-parser:
85+
* * #version
86+
* * #author
87+
* * #email
88+
* * #date
89+
* * #url
90+
* * #short_copyright
91+
* * #long_copyright
92+
* * #citation
93+
*
8094
* \remark For a complete overview, take a look at \ref parser
8195
*
8296
* \stableapi{Since version 1.0.}
@@ -88,43 +102,43 @@ struct parser_meta_data // holds all meta information
88102
* The application name must only contain alpha-numeric characters, '_' or '-',
89103
* i.e. the following regex must evaluate to true: `\"^[a-zA-Z0-9_-]+$\"`.
90104
*/
91-
std::string app_name;
105+
std::string app_name{};
92106

93107
//!\brief The version information `MAJOR.MINOR.PATH` (e.g. 3.1.3)
94-
std::string version;
108+
std::string version{};
95109

96110
//!\brief A short description of the application (e.g. "A tool for mapping reads to the genome").
97-
std::string short_description;
111+
std::string short_description{};
98112

99113
//!\brief Your name ;-)
100-
std::string author;
114+
std::string author{};
101115

102116
//!\brief The author's e-mail address for correspondence.
103-
std::string email;
117+
std::string email{};
104118

105119
/*!\brief The date that the application was last updated. Keep this updated,
106120
*! since it will tell your users that the application is maintained.
107121
*/
108-
std::string date;
122+
std::string date{};
109123

110124
//!\brief A link to your github/gitlab project with the newest release.
111-
std::string url;
125+
std::string url{};
112126

113127
//!\brief Brief copyright (and/or license) information.
114-
std::string short_copyright;
128+
std::string short_copyright{};
115129

116130
/*!\brief Detailed copyright information that will be displayed
117131
* when the user specifies "--copyright" on the command line.
118132
*/
119-
std::string long_copyright;
133+
std::string long_copyright{};
120134

121135
//!\brief How users shall cite your application.
122-
vector_of_string citation;
136+
vector_of_string citation{};
123137

124138
/*!\brief The title of your man page when exported by specifying
125139
* "--export-help man" on the common line.
126140
*/
127-
std::string man_page_title;
141+
std::string man_page_title{};
128142

129143
//!\brief The man page section info (type `man man` on the command line for more information).
130144
unsigned man_page_section{1};
@@ -134,18 +148,22 @@ struct parser_meta_data // holds all meta information
134148
* to the description vector will be treated as a paragraph and
135149
* is separated by a new line.
136150
*/
137-
std::vector<std::string> description;
151+
std::vector<std::string> description{};
138152

139153
/*!\brief Add lines of usage to the synopsis section of the help page (e.g.
140154
* "./my_read_mapper [OPTIONS] FILE1 FILE1").
141155
*/
142-
std::vector<std::string> synopsis;
156+
std::vector<std::string> synopsis{};
143157

144158
/*!\brief Provide some examples on how to use your tool and what standard
145159
* parameters might be appropriate in different cases (e.g.
146160
* "./my_read_mapper -s 3 --my_flag path/infile1").
147161
*/
148-
std::vector<std::string> examples;
162+
std::vector<std::string> examples{};
163+
164+
//!\cond
165+
constexpr friend bool operator==(parser_meta_data, parser_meta_data) = default;
166+
//!\endcond
149167
};
150168

151169
} // namespace sharg

include/sharg/parser.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ namespace sharg
136136
* which means that applications ship with less bugs.
137137
* For privacy implications, please see: https://docs.seqan.de/sharg/main_user/about_update_notifications.html.
138138
*
139+
* In brief, an enabled version check will not transmit any data unless it is *explicitly* granted permission to do so.
140+
* `sharg::update_notifications` therefore controls whether an application may ask for that permission.
141+
*
139142
* Developers that wish to disable this feature permanently can pass an extra constructor argument:
140143
*
141144
* \include doc/tutorial/parser/disable_version_check.cpp
@@ -144,6 +147,7 @@ namespace sharg
144147
*
145148
* * disabling it for a specific application simply by setting the option `--version-check false/0` or
146149
* * disabling it for all applications by setting the `SHARG_NO_VERSION_CHECK` environment variable.
150+
* * selecting `n` (never) when asked by the application.
147151
*
148152
* Note that in case there is no `--version-check` option (display available options with `-h/--help)`,
149153
* then the developer already disabled the version check functionality.
@@ -834,11 +838,24 @@ class parser
834838
if (subcommands.empty())
835839
return false;
836840

841+
auto copy_metadata_to_subparser = [this](parser & sub_parser)
842+
{
843+
sub_parser.info.version = info.version;
844+
sub_parser.info.author = info.author;
845+
sub_parser.info.email = info.email;
846+
sub_parser.info.date = info.date;
847+
sub_parser.info.url = info.url;
848+
sub_parser.info.short_copyright = info.short_copyright;
849+
sub_parser.info.long_copyright = info.long_copyright;
850+
sub_parser.info.citation = info.citation;
851+
};
852+
837853
if (std::ranges::find(subcommands, arg) != subcommands.end())
838854
{
839855
sub_parser = std::make_unique<parser>(info.app_name + "-" + arg.data(),
840856
std::vector<std::string>{it, arguments.end()},
841857
update_notifications::off);
858+
copy_metadata_to_subparser(get_sub_parser());
842859

843860
// Add the original calls to the front, e.g. ["raptor"],
844861
// s.t. ["raptor", "build"] will be the list after constructing the subparser

test/unit/parser/subcommand_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,56 @@ TEST_F(subcommand_test, recursive_subcommands)
271271

272272
EXPECT_EQ(get_parse_cout_on_exit(sub_sub_parser), expected_sub_sub_full_help);
273273
}
274+
275+
TEST_F(subcommand_test, copy_meta_data)
276+
{
277+
sharg::parser_meta_data info{.version = "1.0.0",
278+
.author = "SeqAn-Team",
279+
.email = "[email protected]",
280+
.date = "1970-01-01",
281+
.url = "example.org",
282+
.short_copyright = "BSD 3-Clause",
283+
.long_copyright = "BSD 3-Clause Text",
284+
.citation = "Cite me!"};
285+
286+
auto parser = get_subcommand_parser({"index", "--help"}, {"index"});
287+
info.app_name = parser.info.app_name;
288+
parser.info = info;
289+
EXPECT_EQ(parser.info.app_name, "test_parser");
290+
ASSERT_EQ(parser.info, info); // Sanity check for test setup
291+
EXPECT_NO_THROW(parser.parse());
292+
293+
auto & sub_parser = parser.get_sub_parser();
294+
EXPECT_EQ(sub_parser.info.app_name, "test_parser-index");
295+
info.app_name = sub_parser.info.app_name;
296+
EXPECT_EQ(sub_parser.info, info);
297+
298+
std::string expected_sub_full_help = "test_parser-index\n"
299+
"=================\n"
300+
"\n"
301+
"OPTIONS\n"
302+
"\n"
303+
+ basic_options_str
304+
+ "\n"
305+
"VERSION\n"
306+
" Last update: 1970-01-01\n"
307+
" test_parser-index version: 1.0.0\n"
308+
" Sharg version: "
309+
+ sharg::sharg_version_cstring
310+
+ "\n"
311+
"\n"
312+
"URL\n"
313+
" example.org\n"
314+
"\n"
315+
"LEGAL\n"
316+
" test_parser-index Copyright: BSD 3-Clause\n"
317+
" Author: SeqAn-Team\n"
318+
" Contact: [email protected]\n"
319+
" SeqAn Copyright: 2006-2025 Knut Reinert, FU-Berlin; released under the\n"
320+
" 3-clause BSDL.\n"
321+
" In your academic works please cite:\n"
322+
" [1] Cite me!\n"
323+
" For full copyright and/or warranty information see --copyright.\n";
324+
325+
EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_full_help);
326+
}

0 commit comments

Comments
 (0)