diff --git a/doc/templates/command/arguments.hpp b/doc/templates/command/arguments.hpp index 4ce44522c..a3e98e7a1 100644 --- a/doc/templates/command/arguments.hpp +++ b/doc/templates/command/arguments.hpp @@ -1,11 +1,9 @@ #ifndef DNF5_COMMANDS_TEMPLATE_ARGUMENTS_HPP #define DNF5_COMMANDS_TEMPLATE_ARGUMENTS_HPP - #include #include - namespace dnf5 { // This implementation is needed only if you are using unique_ptr as the type @@ -21,5 +19,4 @@ class BarOption : public libdnf5::cli::session::BoolOption { } // namespace dnf5 - -#endif // DNF_COMMANDS_DOWNLOAD_TEMPLATE_ARGUMENTS_HPP +#endif // DNF_COMMANDS_TEMPLATE_ARGUMENTS_HPP diff --git a/doc/templates/command/template.cpp b/doc/templates/command/template.cpp index 769d52eb3..42631662f 100644 --- a/doc/templates/command/template.cpp +++ b/doc/templates/command/template.cpp @@ -1,3 +1,5 @@ +// Adjust :lines: in template-command.rst if removing/modifying these comment lines! +// clang-format off #include "template.hpp" #include @@ -6,6 +8,15 @@ namespace dnf5 { using namespace libdnf5::cli; +void TemplateCommand::set_parent_command() { + auto * parent_cmd = get_session().get_argument_parser().get_root_command(); + auto * this_cmd = get_argument_parser_command(); + parent_cmd->register_command(this_cmd); + + auto & group = parent_cmd->get_group("software_management_commands"); + group.register_argument(this_cmd); +} + void TemplateCommand::set_argument_parser() { // Context is the main object in dnf5. // It contains useful functions and pieces of information necessary to run @@ -16,37 +27,42 @@ void TemplateCommand::set_argument_parser() { auto & ctx = get_context(); auto & parser = ctx.get_argument_parser(); - auto & cmd = *get_argument_parser_command(); + auto & this_cmd = *get_argument_parser_command(); - // Add template command to the Parser + // Configure 'template' command in the Parser // - // Set a description that would be displayed in the second column of the - // help message would also add the command to the parser - cmd.set_short_description("A command that prints its name and arguments' name"); + // Set a description that would be displayed in the second column of + // the main help message. + this_cmd.set_description("A command that prints its name and arguments' name"); - // Add foo and bar options + // Add '--foo' and '--bar' options // // Option 1: as said in the header file here you should handle the pointer // by giving up the ownership to dnf5's parser. // Set the default value here. foo_option = dynamic_cast( - parser.add_init_value(std::unique_ptr(new libdnf5::OptionBool(false)))); + parser.add_init_value( + std::unique_ptr( + new libdnf5::OptionBool(false)))); // Create an option by giving it a name. It will be shown in the help message. - // Set long name, description and constant value. - // Link the option to the TemplateCommand's class member. auto foo = parser.add_new_named_arg("foo"); + // Set the long name for the option. foo->set_long_name("foo"); - foo->set_short_description("print foo"); + // Set the option's description (for the help message). + foo->set_description("print foo"); + // Set the constant value. This is the value assigned when an option + // which takes no value arguments appears on the command line. foo->set_const_value("true"); + // Link the option to the TemplateCommand's class member. foo->link_value(foo_option); - // Register the argument to the command template. - cmd.register_named_arg(foo); + // Register the '--foo' argument to the 'template' command. + this_cmd.register_named_arg(foo); // Option 2: create a unique_ptr of type BarOption. // The long name, description, and other values were set in - // dnf5/command/arguments.hpp + // template.hpp when we derived the BarOption class. bar_option = std::make_unique(*this); } diff --git a/doc/templates/command/template.hpp b/doc/templates/command/template.hpp index 233b29bbd..0b985b79a 100644 --- a/doc/templates/command/template.hpp +++ b/doc/templates/command/template.hpp @@ -9,7 +9,6 @@ #include #include - namespace dnf5 { // This template aims to explain how to add a new command to dnf5. @@ -18,20 +17,49 @@ namespace dnf5 { class TemplateCommand : public Command { public: // The command name is set directly in the constructor. - explicit TemplateCommand(Command & parent) : Command(parent, "template") {} + explicit TemplateCommand(Context & context) : Command(context, "template") {} + + // This method needs to be overridden to register the command with + // the dnf5 command-line parser, and place the command in one of + // the standard command groups. + // + // Every top-level command will have a set_parent_command method. + // Subcommands will not, their parent command's register_subcommands() + // method is used to register them. + void set_parent_command() override; // This method needs to be overridden to define the structure of the - // command such as description, options or sub-commands. + // command such as description and options. void set_argument_parser() override; + // This method MAY be overridden in a top-level command which has + // subcommands, to register them using register_subcommand(). + // void register_subcommands() override; + // This method needs to be overridden to run the command. void run() override; + // This method MAY be overridden to perform any configuration + // needed by the command. + // void configure() override; + + // This method MAY be overridden to perform any pre-configuration + // needed by the command. + // void pre_configure() override; + + // Not every command will need a pre_configure or configure method, + // and few will need both. + // + // A common pattern in commands that have subcommands is to define + // the top-level command's pre_configure as containing only + // throw_missing_command(). This ensures that using the command + // without one of its subcommands will be treated as an error. + private: // There are two ways to specify options for a command. // Option 1: C++ Pointer. - // Create a OptionBool pointer for the option you need. + // Create an OptionBool pointer for the option you need. // // Using a pure C++ pointer is safe here since the OptionBool class // will take care of moving the pointer ownership to the parser, which will @@ -39,17 +67,15 @@ class TemplateCommand : public Command { libdnf5::OptionBool * foo_option{nullptr}; // Option 2: STL Unique Pointer - // Create a unique_ptr + // Create a std::unique_ptr // // This might be needed in case you need full control over the options and // do not want dnf5's parser to handle it. - // To use a unique_ptr, BarOption has to be defined (see the file - // dnf5/commands/arguments.hpp) + // To use a unique_ptr, BarOption has to be defined. + // A boolean BarOption is defined in the accompanying "arguments.hpp". std::unique_ptr bar_option{nullptr}; }; - } // namespace dnf5 - #endif // DNF5_COMMANDS_TEMPLATE_TEMPLATE_HPP diff --git a/doc/templates/template-command.rst b/doc/templates/template-command.rst index fed5f86aa..384682a9a 100644 --- a/doc/templates/template-command.rst +++ b/doc/templates/template-command.rst @@ -11,26 +11,42 @@ This page focuses on how to write a command with two options in dnf5. the snippets, following the directory structure and naming shown above each one. -``dnf5/command/template.hpp`` + +The command header +------------------ .. literalinclude:: command/template.hpp :language: c++ :linenos: - :lines: 2,4- + :caption: ``dnf5/command/template.hpp`` -``dnf5/command/template.cpp`` +The command source +------------------ .. literalinclude:: command/template.cpp :language: c++ :linenos: - :lines: 2,4- + :lines: 3- + :caption: ``dnf5/command/template.cpp`` -``dnf5/command/arguments.hpp`` +The argument class(es) +---------------------- .. literalinclude:: command/arguments.hpp :language: c++ :linenos: - :lines: 2,4- + :caption: ``dnf5/command/arguments.hpp`` + +Direct integration into dnf5 codebase +------------------------------------- + +.. CAUTION:: + + If you are writing an external command to be included in a dnf5 + plugin, **STOP** here and move on to the :ref:`dnf5 plugin template`. + The remainder of this page is only applicable when writing commands + to be included directly in the dnf5 codebase (in the ``dnf5/commands/`` + subdirectory). The command must be included and registered in ``dnf5/main.cpp`` @@ -39,8 +55,9 @@ The command must be included and registered in ``dnf5/main.cpp`` // new commands must be included in main.cpp #include "commands/template/template.hpp" - // commands must be registered like this - register_subcommand(std::make_unique(*this), software_management_commands_group); + // commands are registered in the add_commands() function + context.add_and_initialize_command( + std::make_unique(context)); Following this example you should have an output like this. @@ -52,13 +69,14 @@ Following this example you should have an output like this. install Install software upgrade Upgrade software ... - template A command that prints its name and arguments' name + template A command that prints its name and arguments' + name .. code-block:: $ dnf5 template --help Usage: - dnf5 template [GLOBAL OPTIONS] [OPTIONS] [ARGUMENTS] + dnf5 [GLOBAL OPTIONS] template [OPTIONS] Options: --bar print bar diff --git a/doc/templates/template-dnf5-plugin.rst b/doc/templates/template-dnf5-plugin.rst index 20f2e54cd..b1eca12c9 100644 --- a/doc/templates/template-dnf5-plugin.rst +++ b/doc/templates/template-dnf5-plugin.rst @@ -1,3 +1,5 @@ +.. _dnf5 plugin template: + DNF5 Plugin Template ====================