ArgumentParser: Add support for version information
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
0c1d33f2ec
commit
80914f0bb9
@ -10,6 +10,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Encode or decode Base64 data. If not given a file, reads from standard input.");
|
||||
parser.add_system_program_info("base64"_sv);
|
||||
parser.add_positional_argument(path, "file", "-"_sv);
|
||||
parser.add_switch_argument(decode, 'd', "decode", "decode data");
|
||||
parser.add_switch_argument(allow_garbage, 'i', "ignore-garbage", "when decoding, ignore non-base64 characters");
|
||||
|
@ -27,6 +27,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Concatenate files to standard output."_sv);
|
||||
parser.add_system_program_info("cat"_sv);
|
||||
parser.add_positional_argument(filename, "file"_sv, "-"_sv);
|
||||
Vector<StringView> extra_files = TRY(parser.parse(argc, argv));
|
||||
|
||||
|
@ -10,6 +10,7 @@ int main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Change the permissions of a file."_sv);
|
||||
parser.add_system_program_info("chmod"_sv);
|
||||
parser.add_positional_argument(mode_string, "mode"_sv, true);
|
||||
parser.add_positional_argument(path, "path"_sv, true);
|
||||
parser.parse(argc, argv);
|
||||
|
@ -12,6 +12,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Change the owner and group of a file."_sv);
|
||||
parser.add_system_program_info("chown"_sv);
|
||||
parser.add_positional_argument(user_and_group, "owner"_sv, true);
|
||||
parser.add_positional_argument(path, "path"_sv, true);
|
||||
parser.parse(argc, argv);
|
||||
|
@ -11,6 +11,7 @@ int main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Display the current (or another) date and time."_sv);
|
||||
parser.add_system_program_info("date"_sv);
|
||||
parser.add_value_argument(date, 'd', "date"_sv, true,
|
||||
"the UNIX timestamp to display instead of the current time"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
@ -10,6 +10,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Edit a file using basic line-based shell editing."_sv);
|
||||
parser.add_system_program_info("edit"_sv);
|
||||
parser.add_positional_argument(pathname, "path"_sv, true);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
|
@ -13,6 +13,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("List files contained in a directory (defaults to '.', the current directory)"_sv);
|
||||
parser.add_system_program_info("ls"_sv);
|
||||
parser.add_positional_argument(pathname, "directory"_sv, "."_sv);
|
||||
parser.add_switch_argument(show_all, 'a', "all"_sv, "also list hidden files (whose filename begins with a dot)"_sv);
|
||||
parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv, "list all files except '.' and '..'"_sv);
|
||||
|
@ -31,6 +31,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Create directories."_sv);
|
||||
parser.add_system_program_info("mkdir"_sv);
|
||||
parser.add_positional_argument(path, "path"_sv, true);
|
||||
parser.add_positional_argument(mode_string, "mode"_sv, "755"_sv);
|
||||
parser.add_switch_argument(recursive, 'p', "parents"_sv,
|
||||
|
@ -8,6 +8,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Remove a path from the file system."_sv);
|
||||
parser.add_system_program_info("rm"_sv);
|
||||
parser.add_positional_argument(path, "path"_sv, true);
|
||||
parser.add_switch_argument(recursive, 'r', "recursive"_sv,
|
||||
"remove a directory recursively (by default, rm removes only empty directories)"_sv);
|
||||
|
@ -46,6 +46,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("The Luna system's command shell."_sv);
|
||||
parser.add_system_program_info("sh"_sv);
|
||||
parser.add_positional_argument(path, "path"_sv, "-"_sv);
|
||||
parser.add_value_argument(command, 'c', "command"_sv, true, "execute a single command and then exit"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
@ -19,6 +19,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Display file status.");
|
||||
parser.add_system_program_info("stat"_sv);
|
||||
parser.add_positional_argument(path, "path", true);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
|
@ -63,6 +63,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Switch to a different user (by default, root)."_sv);
|
||||
parser.add_system_program_info("su"_sv);
|
||||
parser.add_positional_argument(name, "name"_sv, "root"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
|
@ -24,6 +24,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Print system information. If given no options, defaults to -s."_sv);
|
||||
parser.add_system_program_info("uname"_sv);
|
||||
parser.add_switch_argument(all, 'a', "all"_sv, "print all information"_sv);
|
||||
parser.add_switch_argument(kernel_name, 's', "kernel-name"_sv, "print the kernel name"_sv);
|
||||
parser.add_switch_argument(node_name, 'n', "nodename"_sv, "print the network hostname"_sv);
|
||||
|
@ -7,7 +7,7 @@ namespace os
|
||||
class ArgumentParser
|
||||
{
|
||||
public:
|
||||
ArgumentParser(bool add_help = true);
|
||||
ArgumentParser();
|
||||
|
||||
void add_description(StringView description);
|
||||
|
||||
@ -23,6 +23,22 @@ namespace os
|
||||
|
||||
Result<Vector<StringView>> parse(int argc, char* const* argv);
|
||||
|
||||
struct ProgramInfo
|
||||
{
|
||||
StringView name;
|
||||
StringView version;
|
||||
StringView copyright;
|
||||
StringView license;
|
||||
StringView authors;
|
||||
StringView package;
|
||||
};
|
||||
|
||||
void add_program_info(ProgramInfo info);
|
||||
|
||||
/* Used from programs that are part of the Luna source tree, to add the same version info for all programs.
|
||||
* Should not be used otherwise. */
|
||||
void add_system_program_info(StringView name);
|
||||
|
||||
private:
|
||||
struct PositionalArgument
|
||||
{
|
||||
@ -53,11 +69,16 @@ namespace os
|
||||
Result<void> usage(StringView program_name);
|
||||
void short_usage(StringView program_name);
|
||||
|
||||
void version();
|
||||
|
||||
Vector<PositionalArgument> m_positional_args;
|
||||
Vector<SwitchArgument> m_switch_args;
|
||||
Vector<ValueArgument> m_value_args;
|
||||
ProgramInfo m_program_info;
|
||||
StringView m_description = {};
|
||||
bool m_add_short_help_flag { false };
|
||||
bool m_add_long_help_flag { false };
|
||||
bool m_add_short_version_flag { false };
|
||||
bool m_add_long_version_flag { false };
|
||||
};
|
||||
}
|
||||
|
@ -2,10 +2,11 @@
|
||||
#include <os/ArgumentParser.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
namespace os
|
||||
{
|
||||
ArgumentParser::ArgumentParser(bool add_help) : m_add_short_help_flag(add_help), m_add_long_help_flag(add_help)
|
||||
ArgumentParser::ArgumentParser() : m_add_short_help_flag(true), m_add_long_help_flag(true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,6 +35,8 @@ namespace os
|
||||
|
||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||
|
||||
return m_switch_args.try_append(move(arg));
|
||||
}
|
||||
@ -45,6 +48,8 @@ namespace os
|
||||
|
||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||
|
||||
return m_value_args.try_append(move(arg));
|
||||
}
|
||||
@ -56,10 +61,38 @@ namespace os
|
||||
|
||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||
|
||||
return m_value_args.try_append(move(arg));
|
||||
}
|
||||
|
||||
constexpr auto copyright_text = "Copyright (C) 2023, the Luna authors.";
|
||||
constexpr auto license_text = "Licensed under the BSD-2 license <https://opensource.org/license/bsd-2-clause/>";
|
||||
|
||||
void ArgumentParser::add_program_info(ProgramInfo info)
|
||||
{
|
||||
m_program_info = info;
|
||||
m_add_short_version_flag = m_add_long_version_flag = true;
|
||||
}
|
||||
|
||||
void ArgumentParser::add_system_program_info(StringView name)
|
||||
{
|
||||
static utsname info;
|
||||
check(uname(&info) == 0);
|
||||
|
||||
ProgramInfo system_info {
|
||||
.name = name,
|
||||
.version = info.release,
|
||||
.copyright = copyright_text,
|
||||
.license = license_text,
|
||||
.authors = {},
|
||||
.package = "Luna system",
|
||||
};
|
||||
|
||||
add_program_info(system_info);
|
||||
}
|
||||
|
||||
static bool looks_like_short_flag(StringView arg)
|
||||
{
|
||||
return arg.length() > 1 && arg[0] == '-';
|
||||
@ -107,6 +140,7 @@ namespace os
|
||||
bool found = false;
|
||||
|
||||
if (m_add_long_help_flag && flag == "help"_sv) { TRY(usage(program_name)); }
|
||||
if (m_add_long_version_flag && flag == "version"_sv) { version(); }
|
||||
|
||||
for (const auto& current : m_switch_args)
|
||||
{
|
||||
@ -144,6 +178,7 @@ namespace os
|
||||
bool found = false;
|
||||
|
||||
if (m_add_short_help_flag && c == 'h') { TRY(usage(program_name)); }
|
||||
if (m_add_short_version_flag && c == 'v') { version(); }
|
||||
|
||||
// Last flag, this could be a value flag
|
||||
if (j + 1 == flags.length())
|
||||
@ -284,6 +319,35 @@ namespace os
|
||||
}
|
||||
}
|
||||
|
||||
if (m_add_short_help_flag && m_add_long_help_flag)
|
||||
printf(" -h, --%-20s %s\n", "help", "show this help message and exit");
|
||||
else if (m_add_long_help_flag)
|
||||
printf(" --%-20s %s\n", "help", "show this help message and exit");
|
||||
else
|
||||
printf(" -%-25c %s\n", 'h', "show this help message and exit");
|
||||
|
||||
if (m_add_short_version_flag && m_add_long_version_flag)
|
||||
printf(" -v, --%-20s %s\n", "version", "show version information and exit");
|
||||
else if (m_add_long_version_flag)
|
||||
printf(" --%-20s %s\n", "version", "show version information and exit");
|
||||
else
|
||||
printf(" -%-25c %s\n", 'v', "show version information and exit");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ArgumentParser::version()
|
||||
{
|
||||
if (m_program_info.package.is_empty())
|
||||
printf("%s %s\n", m_program_info.name.chars(), m_program_info.version.chars());
|
||||
else
|
||||
printf("%s (%s) %s\n", m_program_info.name.chars(), m_program_info.package.chars(),
|
||||
m_program_info.version.chars());
|
||||
|
||||
printf("%s\n%s\n", m_program_info.copyright.chars(), m_program_info.license.chars());
|
||||
|
||||
if (!m_program_info.authors.is_empty()) printf("\n%s\n", m_program_info.authors.chars());
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user